NIO:即非阻塞式IO

视频教程:   https://chuanke.baidu.com/v1982732-211322-1316084.html

使用步骤:

1、创建 ServerSocketChannel 和业务处理线程池。
2、绑定监听端口,并配置为非阻塞模式。
3、创建 多路复用器Selector,将之前创建的 ServerSocketChannel 注册到 Selector 上,监听 SelectionKey.OP_ACCEPT。
4、循环执行 Selector.select() 方法,轮询就绪的 Channel。
5、Selector轮询就绪的 Channel 时,如果是处于 OP_ACCEPT 状态,说明是新的客户端接入,调用 ServerSocketChannel.accept 接收新的客户端。
6、设置新接入的 SocketChannel 为非阻塞模式,并注册到 Selector 上,监听 OP_READ。
7、如果Selector轮询的 Channel 状态是 OP_READ,说明有新的就绪数据包需要读取,则构造 ByteBuffer 对象,读取数据。

先启动服务端,不停监听客户端连接

服务端代码

  1. import java.io.IOException;
  2. import java.net.InetSocketAddress;
  3. import java.nio.ByteBuffer;
  4. import java.nio.channels.SelectionKey;
  5. import java.nio.channels.Selector;
  6. import java.nio.channels.ServerSocketChannel;
  7. import java.nio.channels.SocketChannel;
  8. import java.util.Iterator;
  9.  
  10. public class NIOServer {
  11.  
  12. /*标识数字*/
  13. private int flag = ;
  14. /*缓冲区大小*/
  15. private int BLOCK = ;
  16. /*接受数据缓冲区*/
  17. private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
  18. /*发送数据缓冲区*/
  19. private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
  20. //选择器
  21. private Selector selector;
  22.  
  23. public NIOServer(int port) throws IOException {
  24. //1. 获取通道, 打开服务器套接字通道
  25. ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
  26. //2. 切换到非阻塞模式
  27. serverSocketChannel.configureBlocking(false);
  28. //3. 绑定连接的端口
  29. serverSocketChannel.socket().bind(new InetSocketAddress(port));
  30. //4. 获取选择器
  31. selector = Selector.open();
  32. //5. 通道注册到选择器上,指定监听事件:接收。……等待连接
  33. serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
  34.  
  35. System.out.println("Server Start----8888:");
  36. }
  37.  
  38. //监听
  39. public void listen() throws IOException {
  40. while(true) {
  41. //6. 循环获取选择器上已经“准备就绪”的事件,返回的int值表示有多少个通道在上一次select后发生了注册事件
  42. int nKeys = selector.select();
  43. if(nKeys>){
  44. //7. 获取当前选择器中所有注册的选择键(已就绪的监听事件)
  45. Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
  46. while(iterator.hasNext()){
  47. //8. 获取“准备就绪”的事件
  48. SelectionKey selectionKey = iterator.next();
  49. //9. 判断具体是什么事件准备就绪,开始处理请求
  50. handleKey(selectionKey);
  51. iterator.remove();
  52. }
  53. } else {
  54. try {
  55. Thread.sleep();
  56. } catch (InterruptedException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. }
  61. }
  62.  
  63. // 处理请求
  64. private void handleKey(SelectionKey selectionKey) throws IOException {
  65. // 接受请求
  66. ServerSocketChannel server = null;
  67. SocketChannel client = null;
  68. String receiveText;
  69. String sendText;
  70. int count=;
  71. // 此选择键的通道是否已准备好接受新的套接字连接。
  72. if (selectionKey.isAcceptable()) {
  73. // 返回为之创建此选择键的通道。
  74. server = (ServerSocketChannel) selectionKey.channel();
  75. //10. 若“接收就绪”,获取客户端连接
  76. client = server.accept();
  77. //11. 切换到非阻塞模式
  78. client.configureBlocking(false);
  79. //12. 通道注册到选择器上,指定监听事件:读 就绪
  80. client.register(selector, SelectionKey.OP_READ);
  81. } else if (selectionKey.isReadable()) {
  82. // 返回为之创建此键的通道。
  83. client = (SocketChannel) selectionKey.channel();
  84. //将缓冲区清空以备下次读取
  85. receivebuffer.clear();
  86. //读取服务器发送来的数据到缓冲区中
  87. count = client.read(receivebuffer);
  88. if (count > ) {
  89. receiveText = new String(receivebuffer.array(),,count);
  90. System.out.println("服务器端接受客户端数据--:"+receiveText);
  91. client.register(selector, SelectionKey.OP_WRITE);
  92. }
  93. } else if (selectionKey.isWritable()) {
  94. //将缓冲区清空以备下次写入
  95. sendbuffer.clear();
  96. // 返回为之创建此键的通道。
  97. client = (SocketChannel) selectionKey.channel();
  98. sendText="message from server--" + flag++;
  99. //向缓冲区中输入数据
  100. sendbuffer.put(sendText.getBytes());
  101. //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
  102. sendbuffer.flip();
  103. //输出到通道
  104. client.write(sendbuffer);
  105. System.out.println("服务器端向客户端发送数据--:"+sendText);
  106. client.register(selector, SelectionKey.OP_READ);
  107. }
  108. }
  109.  
  110. public static void main(String[] args) throws IOException {
  111. int port = ;
  112. NIOServer server = new NIOServer(port);
  113. server.listen();
  114. }
  115.  
  116. }

心得:

1、第5步中,先把服务端通道注册到选择器上,该选择器等待accept接收客户端消息

2、转到第9步,处理请求,如果isAcceptable()=true,准备好接收客户端了,获取客户端连接

3、第12步,客户端通道注册到选择器上,并指定监听。然后,继续走到listen()方法的循环体中,

4、 这次循环中,上面已获取客户端连接,nKeys >0了,selectionKey 是监听

5、又到第9步isReadable()=true,说明是读事件,开始操作数据,通道读取缓冲区

客户端代码

  1. import java.io.IOException;
  2. import java.net.InetSocketAddress;
  3. import java.nio.ByteBuffer;
  4. import java.nio.channels.SelectionKey;
  5. import java.nio.channels.Selector;
  6. import java.nio.channels.SocketChannel;
  7. import java.util.Iterator;
  8. import java.util.Set;
  9.  
  10. public class NIOClient {
  11.  
  12. /*标识数字*/
  13. private static int flag = ;
  14. /*缓冲区大小*/
  15. private static int BLOCK = ;
  16. /*接受数据缓冲区*/
  17. private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
  18. /*发送数据缓冲区*/
  19. private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
  20. /*服务器端地址*/
  21. private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress("127.0.0.1", );
  22.  
  23. public static void main(String[] args) throws IOException {
  24. // TODO Auto-generated method stub
  25. // 打开socket通道
  26. SocketChannel socketChannel = SocketChannel.open();
  27. // 设置为非阻塞方式
  28. socketChannel.configureBlocking(false);
  29. // 打开选择器
  30. Selector selector = Selector.open();
  31. // 注册连接服务端socket动作
  32. socketChannel.register(selector, SelectionKey.OP_CONNECT);
  33. // 连接
  34. socketChannel.connect(SERVER_ADDRESS);
  35. // 分配缓冲区大小内存
  36.  
  37. Set<SelectionKey> selectionKeys;
  38. Iterator<SelectionKey> iterator;
  39. SelectionKey selectionKey;
  40. SocketChannel client;
  41. String receiveText;
  42. String sendText;
  43. int count=;
  44.  
  45. while (true) {
  46. //选择一组键,其相应的通道已为 I/O 操作准备就绪。
  47. //此方法执行处于阻塞模式的选择操作。
  48. selector.select();
  49. //返回此选择器的已选择键集。
  50. selectionKeys = selector.selectedKeys();
  51. //System.out.println(selectionKeys.size());
  52. iterator = selectionKeys.iterator();
  53. while (iterator.hasNext()) {
  54. selectionKey = iterator.next();
  55. if (selectionKey.isConnectable()) {
  56. System.out.println("client connect");
  57. client = (SocketChannel) selectionKey.channel();
  58. // 判断此通道上是否正在进行连接操作。
  59. // 完成套接字通道的连接过程。
  60. if (client.isConnectionPending()) {
  61. client.finishConnect();
  62. System.out.println("完成连接!");
  63. sendbuffer.clear();
  64. sendbuffer.put("Hello,Server".getBytes());
  65. sendbuffer.flip();
  66. client.write(sendbuffer);
  67. }
  68. client.register(selector, SelectionKey.OP_READ);
  69. } else if (selectionKey.isReadable()) {
  70. client = (SocketChannel) selectionKey.channel();
  71. //将缓冲区清空以备下次读取
  72. receivebuffer.clear();
  73. //读取服务器发送来的数据到缓冲区中
  74. count=client.read(receivebuffer);
  75. if(count>){
  76. receiveText = new String( receivebuffer.array(),,count);
  77. System.out.println("客户端接受服务器端数据--:"+receiveText);
  78. client.register(selector, SelectionKey.OP_WRITE);
  79. }
  80.  
  81. } else if (selectionKey.isWritable()) {
  82. sendbuffer.clear();
  83. client = (SocketChannel) selectionKey.channel();
  84. sendText = "message from client--" + (flag++);
  85. sendbuffer.put(sendText.getBytes());
  86. //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
  87. sendbuffer.flip();
  88. client.write(sendbuffer);
  89. System.out.println("客户端向服务器端发送数据--:"+sendText);
  90. client.register(selector, SelectionKey.OP_READ);
  91. }
  92. }
  93. selectionKeys.clear();
  94. }
  95. }
  96.  
  97. }

运行效果:

NIO完成网络通信(一)的更多相关文章

  1. JAVA NIO学习三:NIO 的非阻塞式网络通信

    紧接着上一章,我们继续来研究NIO,上一章中我们讲了NIO 中最常见的操作即文件通道的操作,但实际上NIO的主要用途还是在于网络通信,那么这个时候就会涉及到选择器,这一章我们就会对其进行讲解操作. 一 ...

  2. JAVA NIO学习记录2-非阻塞式网络通信

    一.阻塞与非阻塞 传统的IO 流都是阻塞式的.也就是说,当一个线程调用read() 或write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务.因此,在完成网络通信 ...

  3. 4.NIO的非阻塞式网络通信

    /*阻塞 和 非阻塞 是对于 网络通信而言的*/ /*原先IO通信在进行一些读写操作 或者 等待 客户机连接 这种,是阻塞的,必须要等到有数据被处理,当前线程才被释放*/ /*NIO 通信 是将这个阻 ...

  4. NIO 的非阻塞式网络通信

    1.阻塞与非阻塞   ①  传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write()时, 该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因 ...

  5. JDK10都发布了,nio你了解多少?

    前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 本来我预想是先来回顾一下传统的IO模式的,将传统的IO模式的相关类理清楚(因为IO的类很多). 但是,发现在整理 ...

  6. NIO的初步入门

    NIO java NIO简介 Java NIO 简介 是从java1.4版本开始引入的一个新的IO AP可以替代标准java  IO API NIO与原来的IO有同样的作用和目的,但是使用方式完全不同 ...

  7. Java之NIO

    想要学习Java的Socket通信,首先要学习Java的IO和NIO基础,这方面可以阅读<Java NIO 系列教程>. 下面展示自己代码熟悉Java的NIO编程的笔记. 1.缓冲区(Bu ...

  8. Java NIO -- 阻塞和非阻塞

    传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务.因此,在完成网络通信进行 IO操作 ...

  9. Java中的NIO及IO

    1.概述 Java NIO(New IO) 是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同, ...

随机推荐

  1. servlet容器、IOC容器、SpirngMVC

    servlet容器(这里指tomcat插件)存放servlet对象,而SpringMVC框架整个是一个servlet对象,而IOC容器 在Boot框架中,会存放产生servlet容器的工厂,工厂依据主 ...

  2. C# 读取word2003 并且显示在界面上的方法

    1.新建一个windows窗体程序 2. 引入包WinWordControl.dll 3.添加引用 4.引入组件WinWordControl组件 5.主界面上加入按钮 ,opendialog, win ...

  3. vSphere 扩展硬盘空间

    把所有的snapshot都删除了之后,ssh上去之后,进vmfs目录到client machine的目录. 然后执行下面的方法. 虽然成功了,却没看到有扩展的. 唯一的好处是, vSphone Cli ...

  4. Virtualbox主机和虚拟机之间文件夹共享及双向拷贝

    把文件发到VirtualBox的方法有很多,下面推荐两种: 1.把要共享的文件夹挂载到虚拟机某一个文件上: (1)打开虚拟机的设置,点击左边的“共享文件夹”,点击带加号的文件按钮,在文件夹路径选择要共 ...

  5. LeetCode--443--压缩字符串(未看)

    问题描述: 给定一组字符,使用原地算法将其压缩. 压缩后的长度必须始终小于或等于原数组长度. 数组的每个元素应该是长度为1 的字符(不是 int 整数类型). 在完成原地修改输入数组后,返回数组的新长 ...

  6. canvas学习之饼状图

    接着上一节说,这次我使用canvas绘制了饼状图,主要是SectorGraph.js, 引入 import {canvasPoint} from '../../assets/js/canvas';im ...

  7. Hadoop/HBase Capacity Planning

    http://blog.cloudera.com/blog/2010/08/hadoophbase-capacity-planning/

  8. android-------- 多渠道打包(借助友盟移动统计分析)

    好久没有发博客了,原因是换工作了,今天端午假期,所以来发一篇博客, 多渠道打包,借助友盟移动统计分析,希望对各位有所帮助 多渠道打包的理解: 渠道包就是要在安装包中添加渠道信息,也就是channel, ...

  9. Android--------WebView+H5开发仿美团 预加载,加载失败和重新加载

    Android嵌入式开发已经占大多数了,很多界面都是以网页的形式展示,WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. 本博客主要是模仿美团的旅游出行模块的预加载,网页加载失 ...

  10. python记录_day22 序列化

    序列化是指把内存里的数据类型转换成字符串,以使其能存储到硬盘或通过网络传输到远程,因为硬盘和网络传输时只能接受bytes 一.pickle 把python对象写入到文件中的一种解决方案,但是写入到文件 ...