JAVA NIO的示例

1、JAVA NIO介绍


Java NIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式监察I/O端口,有内容进来会自动通知,这样就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,程序接着做别的事情,当有事件发生时,它会通知程序,传回一组SelectionKey,程序读取这些Key,就会获得刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,接着程序可以处理这些数据。Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,就会站起来报告,交出一把钥匙,让程序通过这把钥匙来读取这个channel的内容。


2、NIO和Standard IO区别


Standard IO把IO抽象成对字节流的读写,在进行IO之前,首先都要创建一个流对象。流对象在进行读写操作时都是按字节来进行的,一个字节一个字节的来读或者写的。
NIO把IO抽象成对块的读写,类似于磁盘的读写,每次IO操作的单位都是一个块,块被读入内存之后的存在形式就是一个字节数组,也就是说NIO可以一次性读/写多个字节。


3、重要概念


Channel
Channel表示程序与某一个IO实体之间的连接,Channel是双向的,不区分输入流和输出流,类似于Unix File的fd。
Buffer
Buffer就是一个字节数组,一块内存。Buffer和Channel每次都是一起使用的,每次都是从一个Channel中读出一个Buffer或者是把一个Buffer写入到一个Channel中。
Selector
Selector是用来实现事件驱动的IO Multiplexing,支持多种实现,BSD用kqueue()的实现,Linux用epoll()实现。


4、代码示例
  

服务器端:SumServer.java类

  1. package nio;
  2. import java.io.IOException;
  3. import java.net.InetSocketAddress;
  4. import java.net.Socket;
  5. import java.nio.ByteBuffer;
  6. import java.nio.IntBuffer;
  7. import java.nio.channels.SelectionKey;
  8. import java.nio.channels.Selector;
  9. import java.nio.channels.ServerSocketChannel;
  10. import java.nio.channels.SocketChannel;
  11. import java.nio.channels.spi.SelectorProvider;
  12. import java.util.Iterator;
  13. import java.util.Set;
  14. /**
  15. * SumServer.java
  16. *
  17. *
  18. * Created
  19. *
  20. * @author 
  21. * @version 1.0
  22. */
  23. publicclass SumServer {
  24. private ByteBuffer _buffer = ByteBuffer.allocate(8);
  25. private IntBuffer _intBuffer = _buffer.asIntBuffer();
  26. private SocketChannel _clientChannel =null;
  27. private ServerSocketChannel _serverChannel =null;
  28. publicvoid start() {
  29. try {
  30. openChannel();
  31. waitForConnection();
  32. } catch (IOException e) {
  33. System.err.println(e.toString());
  34. }
  35. }
  36. privatevoid openChannel()throws IOException {
  37. _serverChannel = ServerSocketChannel.open();
  38. _serverChannel.socket().bind(new InetSocketAddress(10001));
  39. _serverChannel.configureBlocking(false);// 设置为非阻塞形式
  40. System.out.println("服务器通道已经打开");
  41. }
  42. /*
  43. * private void waitForConnection() throws IOException { while (true) {
  44. * _clientChannel = _serverChannel.accept(); if (_clientChannel != null) {
  45. * System.out.println("新的连接加入"); processRequest(); _clientChannel.close(); } } }
  46. */
  47. privatevoid waitForConnection()throws IOException {
  48. Selector acceptSelector = SelectorProvider.provider().openSelector();
  49. /*
  50. * 在服务器套接字上注册selector并设置为接受accept方法的通知。
  51. * 这就告诉Selector,套接字想要在accept操作发生时被放在ready表 上,因此,允许多元非阻塞I/O发生。
  52. */
  53. SelectionKey acceptKey = _serverChannel.register(acceptSelector,
  54. SelectionKey.OP_ACCEPT);
  55. int keysAdded =0;
  56. /* select方法在任何上面注册了的操作发生时返回 */
  57. while ((keysAdded = acceptSelector.select()) >0) {
  58. // 某客户已经准备好可以进行I/O操作了,获取其ready键集合
  59. Set readyKeys = acceptSelector.selectedKeys();
  60. Iterator i = readyKeys.iterator();
  61. // 遍历ready键集合,并处理加法请求
  62. while (i.hasNext()) {
  63. SelectionKey sk = (SelectionKey) i.next();
  64. i.remove();
  65. if (sk.isAcceptable()) {
  66. ServerSocketChannel nextReady = (ServerSocketChannel) sk
  67. .channel();
  68. // 接受加法请求并处理它
  69. _clientChannel = nextReady.accept();
  70. // Socket _clientSocket = _clientChannel.socket();
  71. processRequest();
  72. // _clientSocket.close();
  73. }
  74. }
  75. }
  76. }
  77. privatevoid processRequest()throws IOException {
  78. _buffer.clear();
  79. _clientChannel.read(_buffer);
  80. int result = _intBuffer.get(0) + _intBuffer.get(1);
  81. _buffer.flip();
  82. _buffer.clear();
  83. _intBuffer.put(0, result);
  84. _clientChannel.write(_buffer);
  85. }
  86. publicstaticvoid main(String[] args) {
  87. new SumServer().start();
  88. }
  89. } // SumServer

客户端:SumClient.java类

  1. package nio;
  2. import java.nio.ByteBuffer;
  3. import java.nio.IntBuffer;
  4. import java.nio.channels.SocketChannel;
  5. import java.net.InetSocketAddress;
  6. import java.io.IOException;
  7. /**
  8. * SumClient.java
  9. *
  10. *
  11. * Created
  12. *
  13. * @author 
  14. * @version 1.0
  15. */
  16. publicclass SumClient {
  17. private ByteBuffer _buffer = ByteBuffer.allocate(8);
  18. private IntBuffer _intBuffer;
  19. private SocketChannel _channel;
  20. public SumClient() {
  21. _intBuffer = _buffer.asIntBuffer();
  22. } // SumClient constructor
  23. publicint getSum(int first,int second) {
  24. int result =0;
  25. try {
  26. _channel = connect();
  27. sendSumRequest(first, second);
  28. result = receiveResponse();
  29. } catch (IOException e) {
  30. System.err.println(e.toString());
  31. } finally {
  32. if (_channel !=null) {
  33. try {
  34. _channel.close();
  35. } catch (IOException e) {
  36. }
  37. }
  38. }
  39. return result;
  40. }
  41. private SocketChannel connect()throws IOException {
  42. InetSocketAddress socketAddress = new InetSocketAddress("localhost",
  43. 10001);
  44. return SocketChannel.open(socketAddress);
  45. }
  46. privatevoid sendSumRequest(int first,int second)throws IOException {
  47. _buffer.clear();
  48. _intBuffer.put(0, first);
  49. _intBuffer.put(1, second);
  50. _channel.write(_buffer);
  51. System.out.println("发送加法请求 " + first +"+" + second);
  52. }
  53. privateint receiveResponse()throws IOException {
  54. _buffer.clear();
  55. _channel.read(_buffer);
  56. return _intBuffer.get(0);
  57. }
  58. publicstaticvoid main(String[] args) {
  59. SumClient sumClient = new SumClient();
  60. System.out.println("加法结果为 :" + sumClient.getSum(100,324));
  61. }
  62. } // SumClient

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值