内容还是NIO 而并不是NIO.2 算是对所学的一些总结.
在NIO中 开发TCP程序时会将SocketChannel的OP_READ注册到一个Selector上 selector进行轮训 这是与以往的Socket编程完全不同的新(现在看来已经不能算新啦)的东西.
ServerSocketChannel和原先的ServerSocket相比 增加了一个非堵塞的accept方式(configureBlocking(false)) 和传统的ServerSocket相比 设置成非堵塞方式accept方法会立即返回(没有连接到来就返回null) 所以和SocketChannel一样 他也需要注册到一个Selector上 注册的方法选为OP_ACCEPT.
现在来看看 ServerSocketChannel设置为堵塞(默认)和非堵塞的实现上的区别 以下的图当做草图来用...因为本人不会画uml...画出来多半也是错的 错的地方欢迎打脸..:
非堵塞情况下:
这种情况比较简单 ServerSocketChannel在运行前设置成非堵塞模式 然后注册到实际进行任务处理的Dispather线程的Selector中就可以了
代码如下:
public void start() throws IOException{ ServerSocketChannel ssc=ServerSocketChannel.open(); // 设置端口绑定 ssc.socket().bind(new InetSocketAddress(port)); // 设置地址复用 ssc.socket().setReuseAddress(true); ssc.configureBlocking(false); Dispatcher dispatcher=new NIODispatcher(); dispatcher.register(ssc, SelectionKey.OP_ACCEPT); new Thread(dispatcher).start(); }
对应的dispatcher中的Selector的轮询操作要麻烦一点 因为要判断是Accept的操作 还是Read的操作
Dispatcher中的主要代码如下:
@Override public void run() { while (true) { try { dispatch(); } catch (IOException e) { System.out.println(e); logger.error("NIODispatcher run()", e); } } } private void dispatch() throws IOException { selector.select(); for (Iterator<SelectionKey> itor = selector.selectedKeys().iterator(); itor .hasNext();) { SelectionKey sk = itor.next(); itor.remove(); if (sk.isAcceptable()) { ServerSocketChannel serverSocketChannel = (ServerSocketChannel) sk .channel(); SocketChannel sc = serverSocketChannel.accept(); sc.configureBlocking(false); // 立即注册一个 OP_READ 的SelectionKey, 接收客户端的消息 SelectionKey key = sc.register(selector, SelectionKey.OP_READ); // 如果socket没有连接打开或者sk无效那么下一个 } else if (sk.isReadable()) { SocketChannel sc = (SocketChannel) sk.channel(); ChannelHelper ch = new ChannelHelper(sc, false); try { int count = ch.read(); // 小于零 意味着要么就是传过来的没有信息 要么就是有异常了 if (count < 0) { sk.cancel(); sc.close(); continue; } // 等于零的情况 继续 if (count <= 0) { sk.cancel(); sc.close(); continue; } } catch (Exception e) { logger.error("NIODiapatcher dispatch()", e); sk.cancel(); sc.close(); continue; } RequestHandler handler = new RequestHandler(ch, sk); pool.execute(handler); } } } public void register(ServerSocketChannel ssc, int ops) { try { ssc.register(selector, ops); } catch (ClosedChannelException e) { logger.error("NIODispatcher register", e); } }
以上是非堵塞的实现方式
堵塞的话要多一个接受者的线程来处理到来的连接 并把连接注册到Dispatcher线程的Selector中
堵塞的情况:
图示:
额 图示上都没画箭头 箭头方向是NIO到acceptor和dispatcher acceptor到dispatcher dispatcher负责处理任务(更确切的说是负责任务的派遣)
代码如下:
NIOServer中 不用设置阻塞模式 默认为阻塞:
public void start() throws IOException{ ServerSocketChannel ssc=ServerSocketChannel.open(); // 设置端口绑定 ssc.socket().bind(new InetSocketAddress(port)); // 设置地址复用 ssc.socket().setReuseAddress(true); Dispatcher dispatcher=new NIODispatcher(); Acceptor acceptor=new NIOAcceptor(ssc, dispatcher); new Thread(acceptor).start(); new Thread(dispatcher).start(); }
这里可以看到多了一个Acceptor线程
这个线程的内容很简单 就是负责把得到的连接注册到dispatcher上:
@Override public void run() { while(true){ try { SocketChannel sc=ssc.accept(); sc.configureBlocking(false); dispatcher.register(sc, SelectionKey.OP_READ); } catch (IOException e) { e.printStackTrace(); } } }
最后是dispatcher的代码:
public class NIODispatcher implements Dispatcher { private static final LogUtil logger = new LogUtil(NIODispatcher.class); private ReentrantLock lock = new ReentrantLock(); private Selector selector = null; private ExecutorService pool=null; public NIODispatcher() throws IOException { selector = Selector.open(); pool=Executors.newCachedThreadPool(); } @Override public void run() { while (true) { try { dispatch(); } catch (IOException e) { System.out.println(e); logger.error("NIODispatcher run()", e); } } } private void dispatch() throws IOException { System.out.println("---select操作----"); selector.select(); for (Iterator<SelectionKey> itor = selector.selectedKeys().iterator(); itor .hasNext();) { SelectionKey sk = itor.next(); itor.remove(); SocketChannel sc = (SocketChannel) sk.channel(); // 如果socket没有连接打开或者sk无效那么下一个 System.out.println("---"+sc.getLocalAddress()+" ---"); if (sc.socket().isClosed()|| !sk.isValid() || !sc.isOpen()) { System.out.println("连接无效"); sk.cancel(); sc.close(); continue; } ChannelHelper ch = new ChannelHelper(sc, false); try { int count = ch.read(); //小于等于零 意味着要么就是传过来的没有信息 要么就是有异常了 // 而在读取中做了处理 如果返回是0就是没有信息了 可以安心关闭连接 if (count <= 0) { sk.cancel(); sc.close(); continue; } } catch (Exception e) { logger.error("NIODiapatcher dispatch()", e); sk.cancel(); sc.close(); continue; } RequestHandler handler=new RequestHandler(ch, sk); pool.execute(handler); } lock.lock(); lock.unlock(); } @Override public void register(SocketChannel sc, int ops) { try { lock.lock(); selector.wakeup(); sc.register(selector, ops); } catch (Exception ex) { logger.error("NIODispatcher register", ex); } finally { lock.unlock(); } } }
注意注册的时候要先让Selector wakeup一下 这是为了让在select()方法中堵塞的seletor能去做其他的事情(这里就是SocketChannel注册咯)
更多关于wakeup的解释看:http://www.iteye.com/topic/650195
相关推荐
Java NIO系列教程(一) Java NIO 概述 ...Java NIO系列教程(九) ServerSocketChannel Java NIO系列教程(十) Java NIO DatagramChannel Java NIO系列教程(十一) Pipe Java NIO系列教程(十二) Java NIO与IO
用java编写的nio通信的例子,nio是io编程的新版本,比io较流行。同时本例子是适用socket通信的。可以在此基础上,添加您的个人应用。本例子适用于:java通信的学习者,android平台通信的学习者。
java nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socket
JavaNIO服务器实例Java开发Java经验技巧共6页.pdf.zip
java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现...
jaca视频教程 jaca游戏服务器端开发 Netty NIO AIO Mina视频教程 课程目录: 一、Netty快速入门教程 01、第一课NIO 02、第二课netty服务端 03、第三课netty客户端 04、第四课netty线程模型源码分析(一) 05、...
java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...
java nio连接器,用于网络服务的开发
08-Java NIO-Channel-ServerSocketChannel.mp4 09-Java NIO-Channel-SocketChannel.mp4 10-Java NIO-Channel-DatagramChannel.mp4 11-Java NIO-Channel-分散和聚集.mp4 12-Java NIO-Buffer-概述.mp4 13-Java NIO-...
基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现...
Java NIO原理 图文分析及代码实现
Java NIO英文高清原版
使用Java NIO编写高性能的服务器
java nio入门学习,两个pdfjava nio入门学习,两个pdf
Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据...
java NIO.zip
【IT十八掌徐培成】Java基础第27天-02.NIO-ServerSocketChannel-SocketChannel.zip
Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。 Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,...
Java NIO 深入探讨了 1.4 版的 I/O 新特性,并告诉您如何使用这些特性来极大地提升您所写的 Java 代码的执行效率。这本小册子就程序员所面临的有代表性的 I/O 问题作了详尽阐述,并讲解了 如何才能充分利用新的 I/O ...
讲解了 JavaIO 与 JAVA NIO区别,JAVA NIO设计理念,以及JDK中java NIO中语法的使用