Mina、Netty、Twisted一起学(九):异步IO和回调函数

用过JavaScript或者jQuery的同学都知道,JavaScript特别是jQuery中存在大量的回调函数,比如Ajax、jQuery的动画等。

$.get(url, function() {
	doSomething1(); // (3)
}); // (1)
doSomething2();  // (2)

上面的代码是jQuery的Ajax,因为Ajax是异步的,所以在请求URL的过程中并不会堵塞程序,也就是程序运行到(1)并不用等待Ajax请求的结果,就继续往下运行(2)。而$.get的第二个參数是一个回调函数,当Ajax请求完毕后。才会调用这个回调函数运行(3)。

这个样例仅仅是用来理解一下异步的概念,没玩过JS看不懂的同学也没关系。

在传统的IO(BIO/堵塞IO)中,全部IO操作都会堵塞当前线程,直到操作完毕,全部步骤都是一步一步进行。比如:

OutputStream output = socket.getOutputstream();
out.write(data); // IO操作完毕后返回
out.flush();
System.out.println("消息发送完毕");

可是在异步网络编程中,因为IO操作是异步的,也就是一个IO操作不会堵塞去等待操作结果。程序就会继续向下运行。

在MINA、Netty、Twisted中,非常多网络IO操作都是异步的,比方向网络的还有一端write写数据、client连接server的connect操作等。

比如Netty的write方法(以及writeAndFlush方法),运行完write语句后并不表示数据已经发送出去。而仅仅是開始发送这个数据,程序并不堵塞等待发送完毕,而是继续往下运行。所以假设有某些操作想在write完毕后再运行,比如write完毕后关闭连接。以下这些写法就有问题了,它可能会在数据write出去之前先关闭连接:

Channel ch = ...;
ch.writeAndFlush(message);
ch.close();

那么问题就来了。挖掘机...既然上面的写法不对。那么怎样在IO操作完毕后再做一些其它操作?

当异步IO操作完毕后,不管成功或者失败。都会再通知程序。至于怎样处理发送完毕的通知,在MINA、Netty、Twisted中。都会有相似回调函数的实现方式。

Netty:

在Netty中,write及writeAndFlush方法有个返回值,类型是ChannelFuture。

ChannelFuture的addListener方法能够加入ChannelFutureListener监听器。ChannelFutureListener接口的抽象方法operationComplete会在write完毕(不管成功或失败)时被调用,我们仅仅须要实现这种方法就可以处理一些write完毕后的操作。比如write完毕后关闭连接。

@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg)
		throws UnsupportedEncodingException {

	// 读操作省略...

	// 发送数据到client
	ChannelFuture future = ctx.writeAndFlush("message"); // 返回值类型为ChannelFuture
	future.addListener(new ChannelFutureListener() {

		// write操作完毕后调用的回调函数
		@Override
		public void operationComplete(ChannelFuture future) throws Exception {
			if(future.isSuccess()) { // 是否成功
				System.out.println("write操作成功");
			} else {
				System.out.println("write操作失败");
			}
			ctx.close(); // 假设须要在write后关闭连接,close应该写在operationComplete中。

注意close方法的返回值也是ChannelFuture
			}
	});

}

上面代码中,close操作是在operationComplete中进行,这样能够保证不会在write完毕之前close连接。

注意close关闭连接相同是异步的,其返回值也是ChannelFuture。

MINA:

MINA和Netty相似。session.write返回值是WriteFuture类型。

WriteFuture也能够通过addListener方法加入IoFutureListener监听器。IoFutureListener接口的抽象方法operationComplete会在write完毕(不管成功或失败)时被调用。

假设须要在write完毕后进行一些操作。仅仅需实现operationComplete方法。

@Override
public void messageReceived(IoSession session, Object message)
		throws Exception {

	// 读操作省略...

	// 发送数据到client
	WriteFuture future = session.write("message");
	future.addListener(new IoFutureListener<WriteFuture>() {

		// write操作完毕后调用的回调函数
		@Override
		public void operationComplete(WriteFuture future) {
			if(future.isWritten()) {
				System.out.println("write操作成功");
			} else {
				System.out.println("write操作失败");
			}
		}
	});
}

MINA和Netty不同在于关闭连接的close方法。当中无參数的close()方法已经弃用。而是使用带一个boolean类型參数的close(boolean immediately)方法。

immediately为true则直接关闭连接,为false则是等待全部的异步write完毕后再关闭连接。

所以以下这样的写法是正确的:

session.write("message");
session.close(false); // 尽管write是异步的,可是immediately參数为false会等待write完毕后再关闭连接

Twisted:

在Twisted中,twisted.internet.defer.Deferred相似于MINA、Netty中的Future,能够用于加入在异步IO完毕后的回调函数。

可是Twisted并没有在write方法中返回Deffered。尽管write方法也是异步的。以下就用Twisted实现一个简单的TCPclient来学习Deffered的使用方法。

# -*- coding:utf-8 –*- 

from twisted.internet import reactor
from twisted.internet.protocol import Protocol
from twisted.internet.endpoints import TCP4ClientEndpoint, connectProtocol

class ClientProtocol(Protocol):
    def sendMessage(self):
        self.transport.write("Message") # write也是异步的
        self.transport.loseConnection() # loseConnection会等待write完毕后再关闭连接

# 连接server成功的回调函数
def connectSuccess(p):
    print "connectSuccess"
    p.sendMessage()

# 连接server失败的回调函数
def connectFail(failure):
    print "connectFail"

point = TCP4ClientEndpoint(reactor, "localhost", 8080)
d = connectProtocol(point, ClientProtocol()) # 异步连接到server,返回Deffered
d.addCallback(connectSuccess) # 设置连接成功后的回调函数
d.addErrback(connectFail) # 设置连接失败后的回调函数
reactor.run()

在Twisted中,关闭连接的loseConnection方法会等待异步的write完毕后再关闭,相似于MINA中的session.close(false)。Twisted中想要直接关闭连接能够使用abortConnection,相似MINA中的session.close(true)。

作者:叉叉哥   转载请注明出处:http://blog.csdn.net/xiao__gui/article/details/40016907

时间: 2024-12-23 12:14:23

Mina、Netty、Twisted一起学(九):异步IO和回调函数的相关文章

基于消息机制的异步架构之回调函数注册

/* * akg.h * 业务逻辑注册 * */ #ifndef AKG_H_ #define AKG_H_ #include "conn.h" #include "msgqueue.h" #define MAX_PKG_TYPE (0xffff) extern const uint16 g_akg_connected_id; extern const uint16 g_akg_timeout_id; extern const uint16 g_akg_closed

按照顺序执行异步ajax的回调函数

//按顺序执行多个ajax命令,因为数量不定,所以采用递归 function send(action, arg2) { //将多个命令按顺序封装成数组对象,递归执行 //利用了deferred对象控制回调函数的特点 $.when(send_action(action[0], arg2)) .done(function () { //前一个ajax回调函数完毕之后判断队列长度 if (action.length > 1) { //队列长度大于1,则弹出第一个,继续递归执行该队列 action.sh

Mina、Netty、Twisted一起学(五):整合protobuf

protobuf是谷歌的Protocol Buffers的简称,用于结构化数据和字节码之间互相转换(序列化.反序列化),一般应用于网络传输,可支持多种编程语言. protobuf怎样使用这里不再介绍,本文主要介绍在MINA.Netty.Twisted中怎样使用protobuf,不了解protobuf的同学能够去參考我的还有一篇博文. 在前面的一篇博文中.有介绍到一种用一个固定为4字节的前缀Header来指定Body的字节数的一种消息切割方式.在这里相同要使用到. 仅仅是当中Body的内容不再是字

Mina、Netty、Twisted一起学(十):线程模型

要想开发一个高性能的TCPserver,熟悉所使用框架的线程模型非常重要.MINA.Netty.Twisted本身都是高性能的网络框架,假设再搭配上高效率的代码.才干实现一个高大上的server. 可是假设不了解它们的线程模型.就非常难写出高性能的代码.框架本身效率再高.程序写的太差,那么server总体的性能也不会太高.就像一个电脑,CPU再好.内存小硬盘慢散热差,总体的性能也不会太高. 玩过Android开发的同学会知道,在Android应用中有一个非常重要线程:UI线程(即主线程). UI

Mina、Netty、Twisted一起学(七):公布/订阅(Publish/Subscribe)

消息传递有非常多种方式.请求/响应(Request/Reply)是最经常使用的.在前面的博文的样例中.非常多都是採用请求/响应的方式.当server接收到消息后,会马上write回写一条消息到client. HTTP协议也是基于请求/响应的方式. 可是请求/响应并不能满足全部的消息传递的需求,有些需求可能须要服务端主动推送消息到client,而不是被动的等待请求后再给出响应. 公布/订阅(Publish/Subscribe)是一种server主动发送消息到client的消息传递方式.订阅者Sub

协程,事件,队列,同步,异步,回调函数

协程 什么是协成?单个线程并发的处理多个任务,程序控制协成的切换+保持状态,协成的切换速度非常快,蒙蔽了操作系统的眼睛,让操作系统认为CPU一直在运行 进程或线程都是由操作系统控制CPU来回切换,遇到阻塞就切换执行其他任务,协成是程序控制的,霸占CPU执行任务,会在操作系统控制CPU之前来回切换,操作系统就认为CPU一直在运作 协程的优点: 1.开销小 2.运行速度快 3.协程会长期霸占CPU只执行我程序里的所有任务 协程的缺点: 1.协程属于微并发,处理任务不易过多 2.协程的本质是单线程,无

jQuery 源码解析(八) 异步队列模块 Callbacks 回调函数详解

异步队列用于实现异步任务和回调函数的解耦,为ajax模块.队列模块.ready事件提供基础功能,包含三个部分:Query.Callbacks(flags).jQuery.Deferred(funct)和jQuery.when().本节讲解Callbacks,也就是回调函数列表 回调函数用于管理一组回调函数,支持添加.移除.触发.锁定和禁用回调函数,为jQuery.ajax.jQuery.Deferred()和ready()事件提供基础功能,我们也可以基于它编写新的组件. 使用方法:$.Callb

Mina、Netty、Twisted一起学:实现简单的TCP服务器

MINA.Netty.Twisted为什么放在一起学习?首先,不妨先看一下他们官方网站对其的介绍: MINA: Apache MINA is a network application framework which helps users develop high performance and high scalability network applications easily. It provides an abstract event-driven asynchronous API

Mina、Netty、Twisted一起学(一):实现简单的TCP服务器

MINA.Netty.Twisted为什么放在一起学习?首先,不妨先看一下他们官方网站对其的介绍: MINA: Apache MINA is a network application framework which helps users develop high performance and high scalability network applications easily. It provides an abstract event-driven asynchronous API