对相关类的简单介绍 java.nio.*, 据说它提供了一些更加底层的一些功能,如:类似windows环境下的AsyncSocket类的异步操作的功能,能显著降低server端程序的线程管理开销。 因为大多数应用是建立在TCP之上,所以在此只说说SocketChannel,ServerSocketChannel,Selector和ByteBuffer这几个类.前三个最终都源自channel类。而channel 类,可以理解为在具体I/O或文件对象之上抽象的一个操作对象,我们通过操作channel的读写达到对其对应的文件或I/O对象(包括socket)读写的目的。读写的内容在内存中放在ByteBuffer类提供的缓冲区。总而言之,channel作为一个桥梁,连接了I/O对象和内存中的ByteBuffer,实现了I/O的更高效的存取。 一个基于TCP的服务器端程序,必然有个侦听端和若干个通信端,它们在nio中由对应的ServerSocketChannel 和SocketChannel类来实现。为了达到异步I/O操作的目的,需要Selector类,它能检测到I/O对象的状态。
SocketChannel类是抽象类,通过调用它的静态函数open(),可生成一个SocketChannel对象,该对象对应一个java.net.Socket,可通过SocketChannel.socket()获得,而其对应的Socket也可通过调用函数getChannel()得到已建立的相应SocketChannel。 SocketChannel与它的socket是一一对应的。SocketChannel的操作与Socket也很相似.
ServerSocketChannel也是通过调用它的静态函数open()生成的,只是它不能直接调用bind()函数来绑定一个地址,需要它对应的ServerSocket来完成绑定工作,一般可按如下步骤做:
罗嗦了半天,还是看看最简单的C/S实现吧,服务器提供了基本的回射(echo)功能,其中提供了较详细的注释。
源码分析
1.服务器端:
在当前目录下运行: javac AsynServer.java 后,若无编译出错,接下来可运行: java AsynServer 或 java AsynServer ×××(端口号) 上述服务程序在运行时,可指定其侦听端口,否则程序会取8848为默认端口。
2.客户端的简单示例:
在当前目录下运行: javac AsynClient.java 后,若无编译出错,确认AsyncServer已经运行的情况下,接下来可运行: java AsynClient hostname 或 java AsynClient hostname ×××(端口号) 并按提示进行操作即可。
总结 总的来说,用nio进行网络编程还是很有新意的,服务器端软件能在一个线程中维护与众多客户端的通信连接。笔者在本文中试图用一个典型的回射例子说明如何用nio建立最基本的C/S应用。希望大家能试着用用它。 另外,笔者在实践中也发现nio在应用中存在的一些难题,比如如何应用SocketChannel的继承类,以及如何在socketchannel之上应用SSL(Secure Socket Layer)等等,因而希望这篇文章只是抛砖引玉,引起大家对nio作进一步的讨论。