java线程之五 NIO对象
NIO是相对于IO来说的。因为NIO=new IO。从JDK1.4版本以后引进来的。可以说NIO是对IO的补充,
NIO是对IO的进一步封装,解决了原本IO自身堵塞的问题(虽然可以通过线程来解决,但是占用了大量的CPU资源)
简单来说,NIO有缓存Buffer对象,通过Channel来存储和读写Buffer。提供了Charset对象来实现Unicode与其他字符间
的转换,最后通过Selector来完成非堵塞开发。
关于NIO与IO区别 可以参考以下文章
http://www.dewen.org/q/9648
http://tutorials.jenkov.com/java-nio/nio-vs-io.html
下班了,直接上代码
服务端代码
1 /** 2 * @author draem0507@gmail.com 3 * @TODO java 线程之五 nio nio介绍 在1.4以后的JDK中出现了new io 特性主要表现在 1.非阻塞(不用单独开线程来模拟) 4 * 2.字符转换 3.缓冲及其通道 新增了四个重要的类 1.Buffer 缓冲区 2.Charset 提供了Unicode与其他字符编码之间的转换 5 * 3.Channel 数据传输通道 将Buffer的数据进行写入或则读取 4.Selector 用来支持异步的I/O操作 6 * 参考资料:http://blog.chinaunix.net/uid-24186189-id-2623973.html 7 * @version 1.0 8 * @date 2013-5-8 15:26:45 9 * @blgos http://www.cnblogs.com/draem0507 10 */ 11 public class ServerTest { 12 private ByteBuffer _buffer = ByteBuffer.allocate(16); 13 private IntBuffer _intBuffer = _buffer.asIntBuffer(); 14 private SocketChannel clientChannel; 15 private ServerSocketChannel serverSocketChannel; 16 17 public ServerTest() { 18 } 19 20 private void startServer() { 21 openConnection(); 22 listenConnection(); 23 24 } 25 26 private void listenConnection() { 27 // 单线程模拟 28 29 /* 30 * while (true) { try { clientChannel = serverSocketChannel.accept(); if 31 * (null != clientChannel) { System.out.println("新的客户端连接"); // 进行请求操作 32 * Thread.sleep(5000); 33 * 34 * doRequest(); // 关闭socket clientChannel.close(); } } catch 35 * (IOException e) { // TODO Auto-generated catch block 36 * e.printStackTrace(); } catch (InterruptedException e) { // TODO 37 * Auto-generated catch block e.printStackTrace(); } 38 * } 39 */ 40 // 多线程模式 41 // openConnection方法中开启非堵塞模式 42 // 引入selector 43 try { 44 Selector selector = SelectorProvider.provider().openSelector(); 45 // 注册selector对象到套接字对象并设置为accept 告诉selector套接字对象操作I/O时希望使用非堵塞模式 46 SelectionKey key = serverSocketChannel.register(selector, 47 SelectionKey.OP_ACCEPT); 48 int addKey = 0; 49 while ((addKey = selector.select()) > 0) { 50 51 Set readyKeys = selector.selectedKeys(); 52 Iterator i = readyKeys.iterator(); 53 // 遍历ready键集合,并处理加法请求 54 while (i.hasNext()) { 55 SelectionKey sk = (SelectionKey) i.next(); 56 i.remove(); 57 ServerSocketChannel nextReady = (ServerSocketChannel) sk 58 .channel(); 59 // 接受加法请求并处理它 60 clientChannel = nextReady.accept(); 61 //为了方便测试 这里加入时间 62 63 Thread.sleep(5000); 64 doRequest(); 65 clientChannel.close(); 66 } 67 } 68 } catch (IOException e) { 69 // TODO Auto-generated catch block 70 e.printStackTrace(); 71 } catch (InterruptedException e) { 72 // TODO Auto-generated catch block 73 e.printStackTrace(); 74 } 75 76 } 77 78 private void doRequest() { 79 _buffer.clear(); 80 try { 81 clientChannel.read(_buffer); 82 int req = _intBuffer.get(0); 83 _buffer.flip(); 84 _buffer.clear(); 85 _intBuffer.put(0, req * 2); 86 clientChannel.write(_buffer); 87 88 } catch (IOException e) { 89 // TODO Auto-generated catch block 90 e.printStackTrace(); 91 } 92 93 } 94 95 private void openConnection() { 96 try { 97 serverSocketChannel = ServerSocketChannel.open(); 98 // new ServerSocket(10000);内部也是实现了bind 间接说明NIO是在IO的基础上进行了封装 99 // 而不同的地方不在于如何创建对象 而是对象的读取写入(缓存)监听客户端连接的方式(selector)等区别 100 serverSocketChannel.socket().bind(new InetSocketAddress(10000)); 101 // 非堵塞模式 开关默认 102 serverSocketChannel.configureBlocking(false); 103 104 System.out.println("服务器已经开始连接"); 105 } catch (IOException e) { 106 // TODO Auto-generated catch block 107 e.printStackTrace(); 108 } 109 110 } 111 112 public static void main(String[] args) { 113 new ServerTest().startServer(); 114 } 115 116 }
客户端代码
1 public class ClientTest { 2 private SocketChannel channel; 3 private ByteBuffer _buffer=ByteBuffer.allocate(16); 4 private IntBuffer _intBuffer=_buffer.asIntBuffer(); 5 6 public ClientTest() { 7 } 8 9 private void conn() { 10 11 connServer(); 12 sendRequest(); 13 int resp=receiveRequest(); 14 System.out.println("收到服务端的结果:"+resp); 15 16 } 17 18 private int receiveRequest() { 19 _buffer.clear(); 20 try { 21 channel.read(_buffer); 22 } catch (IOException e) { 23 // TODO Auto-generated catch block 24 e.printStackTrace(); 25 } 26 return _intBuffer.get(0); 27 28 } 29 30 private void sendRequest() { 31 32 _buffer.clear(); 33 int send=(int)(Math.random()*5)+1; 34 _intBuffer.put(0, send); 35 try { 36 channel.write(_buffer); 37 } catch (IOException e) { 38 // TODO Auto-generated catch block 39 e.printStackTrace(); 40 } 41 System.out.println("发送数据:"+send); 42 43 } 44 45 private void connServer() { 46 InetSocketAddress remote = new InetSocketAddress("localhost", 10000); 47 try { 48 channel=SocketChannel.open(remote); 49 } catch (IOException e) { 50 // TODO Auto-generated catch block 51 e.printStackTrace(); 52 } 53 } 54 55 public static void main(String[] args) { 56 new ClientTest().conn(); 57 } 58 59 }