首页 / 软件开发 / JAVA / 运用异步输入输出流编写Socket进程通信
运用异步输入输出流编写Socket进程通信2010-12-14杨健同步?异步输入输出机制的引入在Merlin之前,编写Socket程序是比 较繁琐的工作.因为输入输出都必须同步.这样,对于多客户端客户/服务器模式, 不得不使用多线程.即为每个连接的客户都分配一个线程来处理输入输出.由此而 带来的问题是可想而知的.程序员不得不为了避免死锁,线程安全等问题,进行大 量的编码和测试.很多人都在抱怨为什么不在Java中引入异步输入输出机制.比较 官方的解释是,任何一种应用程序接口的引入,都必须兼容任何操作平台.因为 Java是跨平台的.而当时支持异步输入输出机制的操作平台显然不可能是全部.自 Java 2 Platform以后,分离出J2SE,J2ME,J2EE三种不同类型的应用程序接口,以 适应不同的应用开发.Java标准的制订者们意识到了这个问题,并且支持异步输入 输出机制的操作平台在当今操作平台中处于主流地位.于是,Jdk(J2SE) 的第五次 发布中引入了异步输入输出机制.以前的Socket进程通信程序设计中,一 般客户端和服务器端程序设计如下:服务器端: //服务器 端监听线程
while (true) {
.............
Socket clientSocket;
clientSocket = socket.accept(); //取得客户请求Socket,如果没 有//客户请求连接,线程在此处阻塞
//用取得的Socket 构造输入输出流
PrintStream os = new PrintStream (new
BufferedOutputStream (clientSocket.getOutputStream(),
1024), false);
BufferedReader is = new BufferedReader (new
InputStreamReader (clientSocket.getInputStream()));
//创建客户会话 线程,进行输入输出控制,为同步机制
new ClientSession();
.......
} 客户端: ............
clientSocket = new Socket(HOSTNAME, LISTENPORT);//连接服务器套接字
//用取得的 Socket构造输入输出流
PrintStream os = new PrintStream(new
BufferedOutputStream(clientSocket.getOutputStream (),
1024), false);
BufferedReader is = new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));
//进行输入 输出控制
.......以上代码段只是用同步机制编写 Socket进程通信的一个框架,实际上要考虑的问题要复杂的多(有兴趣的读者可 以参考我的一篇文章《Internet 实时通信系统设计与实现》)。将这样一个框 架列出来,只是为了与用异步机制实现的Socket进程通信进行比较。下面将介绍 使用异步机制的程序设计。用异步输入输出流编写Socket进程通信程序在Merlin中加入了用于实现异步输入输出机制的应用程序接口包: java.nio(新的输入输出包,定义了很多基本类型缓冲(Buffer)), java.nio.channels(通道及选择器等,用于异步输入输出),java.nio.charset (字符的编码解码)。通道(Channel)首先在选择器(Selector)中注册自己感兴 趣的事件,当相应的事件发生时,选择器便通过选择键(SelectionKey)通知已注 册的通道。然后通道将需要处理的信息,通过缓冲(Buffer)打包,编码/解码, 完成输入输出控制。通道介绍:这里主要介绍 ServerSocketChannel和 SocketChannel.它们都是可选择的(selectable)通道, 分别可以工作在同步和异步两种方式下(注意,这里的可选择不是指可以选择两 种工作方式,而是指可以有选择的注册自己感兴趣的事件)。可以用 channel.configureBlocking(Boolean )来设置其工作方式。与以前版本的API相 比较,ServerSocketChannel就相当于ServerSocket(ServerSocketChannel封装 了ServerSocket),而SocketChannel就相当于Socket(SocketChannel封装了 Socket)。当通道工作在同步方式时,编程方法与以前的基本相似,这里主要介 绍异步工作方式。所谓异步输入输出机制,是指在进行输入输出处理时 ,不必等到输入输出处理完毕才返回。所以异步的同义语是非阻塞(None Blocking)。在服务器端,ServerSocketChannel通过静态函数open()返回一个 实例serverChl。然后该通道调用serverChl.socket().bind()绑定到服务器某端 口,并调用register(Selector sel, SelectionKey.OP_ACCEPT)注册 OP_ACCEPT事件到一个选择器中(ServerSocketChannel只可以注册OP_ACCEPT事 件)。当有客户请求连接时,选择器就会通知该通道有客户连接请求,就可以进 行相应的输入输出控制了;在客户端,clientChl实例注册自己感兴趣的事件后 (可以是OP_CONNECT,OP_READ,OP_WRITE的组合),调用clientChl.connect (InetSocketAddress )连接服务器然后进行相应处理。注意,这里的连接是异步 的,即会立即返回而继续执行后面的代码。