首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Java Socket编程(5)NIO

2012-08-25 
Java Socket编程(五)NIO一、服务器端的处理模式1.迭代服务器服务器只有处理完了当前用户的请求后,才会处理

Java Socket编程(五)NIO


一、服务器端的处理模式
1.迭代服务器
服务器只有处理完了当前用户的请求后,才会处理下一请求,因此是迭代式的,在同一线程内处理。
ServerSocket serverSocket = new ServerSocket(port);while(true) {     Socket clientSocket = serverSocket.accept();     ...}

2.一客户一线程
对每个连接的客户端都新建一个线程来处理它的请求。这种处理方式的缺点很明显,当创建出来的同时运行的线程过多时,操作系统大量时间都耗费在线程的切换和状态维护上,而非线程内的请求处理。
ServerSocket serverSocket = new ServerSocket(port);while(true) {     Socket clientSocket = serverSocket.accept();     new HandlerThread(clientSocket).start();     ...}

3.线程池
使用固定数目的线程来监听请求,或者使用JDK的Executor线程池。相比前面两种方法,这种处理方式在并发与性能之间达到了一个平衡,但是它也是有自身的缺点,具体见后文的描述。
final ServerSocket serverSocket = new ServerSocket(port);for (int i = 0; i < poolSize; i++) {     new Thread() {          public void run() {               while (true) {                    Socket clientSocket = serverSocket.accept();                    ...               }          }     }.start();}

4.缺点
类似上述这些基于阻塞式Socket和多线程的处理方式都有很大的缺点:
1.线程池的大小限制了系统可以同时服务的客户端总数。
2.如果想要保证某些连接优先获得服务,线程就很难做到。
3.如果这些线程需要读写共享的资源的话,还需要锁或其他互斥机制来同步。

二、NIO中的Select机制
通过NIO,我们可以很方便地在Java中实现Select机制。Select机制比上述的处理方式好在哪呢?
首先,在Select机制中,我们不需要许多的线程来应对无数客户端的请求。我们通过一次select()调用可以得到一组客户端,而这些客户端都是准备好读写的,因此在后续的读写操作都是非阻塞的。所以这一组准备就绪的客户端读写请求就都交给一个Selector类来处理了,完全的单线程,没有了上面的那些缺点!
此外,定长的Buffer缓冲类替代了流的概念,所以NIO里没有了输入输出流的身影,而是将数据保存到Buffer对象中后,直接写入到Channel中。读取时,也是直接从Channel中读取出Buffer。
public class TCPSelectorServerTest {public static void main(String[] args) throws Exception {Selector selector = Selector.open();int[] ports = { 1234, 5678 };for (int port : ports) {ServerSocketChannel listenChannel = ServerSocketChannel.open();listenChannel.socket().bind(new InetSocketAddress("localhost", port));listenChannel.configureBlocking(false);listenChannel.register(selector, SelectionKey.OP_ACCEPT);}while (true) {if (selector.select(3000) == 0) {System.out.print(".");continue;}Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();while (keyIter.hasNext()) {SelectionKey key = keyIter.next();if (key.isAcceptable()) {SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();clientChannel.configureBlocking(false);clientChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(32));}if (key.isReadable()) {SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = (ByteBuffer) key.attachment();long bytesRead = clientChannel.read(buffer);if (bytesRead == -1)clientChannel.close();elsekey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);}if (key.isValid() && key.isWritable()) {ByteBuffer buffer = (ByteBuffer) key.attachment();buffer.flip();SocketChannel clientChannel = (SocketChannel) key.channel();clientChannel.write(buffer);// No left, no longer interest in writeif (!buffer.hasRemaining())key.interestOps(SelectionKey.OP_READ);buffer.compact();}keyIter.remove();}}}}

热点排行