nio学习(代码片段)

beheaven beheaven     2023-03-14     300

关键词:

1. NIO客户端与服务端网络编程关键:

 理解各个监听事件的驱动事件,总结以下几点:
(1)ServerSocketChannel注册了OP_ACCEPT事件,需要客户端发起连接请求,服务端selector才能监听到(阻塞在selector.select()才能继续执行)
(2)服务端获取客户端SocketChannel,注册读事件后,只有客户端写事件,服务端selector才能监听到(阻塞在selector.select()才能继续执行,读事件是被动的,需要写事件驱动)
(3)不管服务端还是客户端,本端注册的管道写事件,selector马上能监听到(总结:写事件是主动的,只要注册,就能监听到)
(4)SelectionKey.OP_CONNECT(主动事件,客户端注册完之后,本端selector马上能监听到)-->isConnectable()为true
         SelectionKey.OP_ACCEPT(被动事件,需服务端注册accepte事件,还需要客户端发连接请求触发)-->isAcceptable()为true
         SelectionKey.OP_WRITE(主动事件,客户端注册完之后,本端selector马上能监听到)-->isWritable()为true
         SelectionKey.OP_READ(被动事件,需本端注册读事件,并且对端有写事件才触发)-->isReadable()为true

 

2. 服务端代码:

  1 package com.hw.nio;
  2 
  3 import java.io.IOException;  
  4 import java.net.InetSocketAddress;  
  5 import java.net.ServerSocket;  
  6 import java.nio.ByteBuffer;  
  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.util.Iterator;  
 12 import java.util.Set;  
 13 /**
 14  * NIO客户端与服务端网络编程关键:
 15  *  理解各个监听事件的驱动事件,例如:
 16  * (1)ServerSocketChannel注册了OP_ACCEPT事件,需要客户端发起连接请求,服务端selector才能监听到(阻塞在selector.select()才能继续执行)
 17  * (2)服务端获取客户端SocketChannel,注册读事件后,只有客户端写事件,服务端selector才能监听到(阻塞在selector.select()才能继续执行)(总结:读事件是被动的,需要写事件驱动)
 18  * (3)不管服务端还是客户端,本端注册的管道写事件,selector马上能监听到(总结:写事件是主动的,只要注册,就能监听到)
 19  * (4)SelectionKey.OP_CONNECT(主动事件,客户端注册完之后,本端selector马上能监听到)-->isConnectable()为true
 20  *     SelectionKey.OP_ACCEPT(被动事件,需服务端注册accepte事件,还需要客户端发连接请求触发)-->isAcceptable()为true
 21  *     SelectionKey.OP_WRITE(主动事件,客户端注册完之后,本端selector马上能监听到)-->isWritable()为true
 22  *     SelectionKey.OP_READ(被动事件,需本端注册读事件,并且对端有写事件才触发)-->isReadable()为true
 23  * @author thinkpad
 24  *
 25  */
 26 public class NIOServer   
 27       
 28     /*标识数字*/ 
 29     private  int flag = 0;  
 30     /*缓冲区大小*/ 
 31     private  int BLOCK = 4096;  
 32     /*接受数据缓冲区*/ 
 33     private  ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);  
 34     /*发送数据缓冲区*/ 
 35     private  ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);  
 36     private  Selector selector;  
 37  
 38     public NIOServer(int port) throws IOException   
 39         // 打开服务端套接字通道  
 40         ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  
 41         // 服务器配置为非阻塞  
 42         serverSocketChannel.configureBlocking(false);  
 43         // 检索与此通道关联的服务器套接字  
 44         ServerSocket serverSocket = serverSocketChannel.socket();  
 45         // 进行服务的绑定  
 46         serverSocket.bind(new InetSocketAddress(port));  
 47         // 通过open()方法找到Selector  
 48         selector = Selector.open();  
 49         // 注册通道到selector,等待连接
 50         // self:1.如果不注册OP_ACCEPT,即使客户端发连接请求,selector也无法监听到连接事件,导致selector.select()一直阻塞等待
 51         // 2.即使注册了OP_ACCEPTE,客户端如果不发送连接请求,服务端也会一直阻塞在selector.select();
 52         serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 
 53         System.out.println("Server Start----8888:");  
 54       
 55  
 56  
 57     // 监听  
 58     private void listen() throws IOException   
 59         while (true)   
 60             // 选择一组键,并且相应的通道已经打开(服务端如果注册了OP_ACCEPTE,第一次等待客户端连接,若客户端无连接请求,阻塞在此处)
 61             selector.select();  
 62             // 返回此选择器的已选择键集。  
 63             Set<SelectionKey> selectionKeys = selector.selectedKeys();  
 64             Iterator<SelectionKey> iterator = selectionKeys.iterator();  
 65             while (iterator.hasNext())           
 66                 SelectionKey selectionKey = iterator.next();  
 67                 iterator.remove();  
 68                 handleKey(selectionKey);  
 69               
 70           
 71       
 72  
 73     // 处理请求  
 74     private void handleKey(SelectionKey selectionKey) throws IOException   
 75         // 接受请求  
 76         ServerSocketChannel server = null;  
 77         SocketChannel client = null;  
 78         String receiveText;  
 79         String sendText;  
 80         int count=0;  
 81         // 测试此键的通道是否已准备好接受新的套接字连接。  
 82         if (selectionKey.isAcceptable())   
 83             // 返回为之创建此键的通道。  
 84             server = (ServerSocketChannel) selectionKey.channel();  
 85             // 接受到此通道套接字的连接。  
 86             // 此方法返回的套接字通道(如果有)将处于阻塞模式。  
 87             client = server.accept();  
 88             // 配置为非阻塞  
 89             client.configureBlocking(false);  
 90             // 注册到selector,等待连接  
 91             client.register(selector, SelectionKey.OP_READ);  
 92          else if (selectionKey.isReadable())   // 仅仅注册了读事件还不行,还需要客户端写才能触发
 93             // 返回为之创建此键的通道。  
 94             client = (SocketChannel) selectionKey.channel();  
 95             //将缓冲区清空以备下次读取  
 96             receivebuffer.clear();  
 97             //读取服务器发送来的数据到缓冲区中  
 98             count = client.read(receivebuffer);   
 99             if (count > 0)   
100                 receiveText = new String( receivebuffer.array(),0,count);  
101                 System.out.println("服务器端接受客户端数据--:"+receiveText);  
102                 client.register(selector, SelectionKey.OP_WRITE);  
103               
104          else if (selectionKey.isWritable())   
105             //将缓冲区清空以备下次写入  
106             sendbuffer.clear();  
107             // 返回为之创建此键的通道。  
108             client = (SocketChannel) selectionKey.channel();  
109             sendText="message from server--" + flag++;  
110             //向缓冲区中输入数据  
111             sendbuffer.put(sendText.getBytes());  
112              //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位  
113             sendbuffer.flip();  
114             //输出到通道  
115             client.write(sendbuffer);  
116             System.out.println("服务器端向客户端发送数据--:"+sendText);  
117             client.register(selector, SelectionKey.OP_READ);  
118           
119       
120  
121     /**  
122      * @param args  
123      * @throws IOException  
124      */ 
125     public static void main(String[] args) throws IOException   
126         int port = 8888;  
127         NIOServer server = new NIOServer(port);  
128         server.listen();  
129       
130  

3. 客户端代码:

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

4. 测试代码:

 1 package com.hw.nio;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.net.InetSocketAddress;
 6 import java.net.ServerSocket;
 7 import java.net.Socket;
 8 import java.net.SocketAddress;
 9 import java.nio.ByteBuffer;
10 import java.nio.channels.SocketChannel;
11 import java.util.concurrent.TimeUnit;
12 
13 public class NIOTest 
14 
15     public static void client() 
16         ByteBuffer buffer = ByteBuffer.allocate(1024);
17         SocketChannel socketChannel = null;
18         try 
19             socketChannel = SocketChannel.open();
20             socketChannel.configureBlocking(false);
21             socketChannel.connect(new InetSocketAddress("localhost", 8080));
22 
23             if (socketChannel.finishConnect()) 
24                 int i = 0;
25                 while (true) 
26                     TimeUnit.SECONDS.sleep(1);
27                     String info = "I‘m " + i++ + "-th information from client";
28                     buffer.clear();
29                     buffer.put(info.getBytes());
30                     buffer.flip();
31                     while (buffer.hasRemaining()) 
32                         System.out.println(buffer);
33                         socketChannel.write(buffer);
34                     
35                 
36             
37          catch (IOException | InterruptedException e) 
38             e.printStackTrace();
39          finally 
40             try 
41                 if (socketChannel != null) 
42                     socketChannel.close();
43                 
44              catch (IOException e) 
45                 e.printStackTrace();
46             
47         
48     
49 
50     public static void server() 
51         ServerSocket serverSocket = null;
52         InputStream in = null;
53         try 
54             serverSocket = new ServerSocket(8080);
55             int recvMsgSize = 0;
56             byte[] recvBuf = new byte[1024];
57             while (true) 
58                 Socket clntSocket = serverSocket.accept();
59                 SocketAddress clientAddress = clntSocket.getRemoteSocketAddress();
60                 System.out.println("Handling client at " + clientAddress);
61                 in = clntSocket.getInputStream();
62                 while ((recvMsgSize = in.read(recvBuf)) != -1) 
63                     byte[] temp = new byte[recvMsgSize];
64                     System.arraycopy(recvBuf, 0, temp, 0, recvMsgSize);
65                     System.out.println(new String(temp));
66                 
67             
68          catch (IOException e) 
69             e.printStackTrace();
70          finally 
71             try 
72                 if (serverSocket != null) 
73                     serverSocket.close();
74                 
75                 if (in != null) 
76                     in.close();
77                 
78              catch (IOException e) 
79                 e.printStackTrace();
80             
81         
82     
83     public static void main(String[] args) 
84         if("client".equals(args[0])) 
85             client();
86         
87         server();
88         if("server".equals(args[0])) 
89             server();
90         
91     
92 

 

javanio学习(代码片段)

JavaNIO学习为什么要使用NewIO?NIO是jdk1.4加入的新包,NIO的创建目的是为了让java程序员可以实现高速I/O而无需编写自定义的本机代码。NIO将最耗时的I/O操作(即填充和提取缓冲区)转移到操作系统,因而可极大的提高速度。流与... 查看详情

nio流的学习(代码片段)

NIO的使用一)、什么叫NIO?定义:是一套新的JavaI/O标准,在java1.4中被纳入JDK中。二)、NIO的实现方法NIO是基于块的,以块为基本单位处理数据。标准的I/O是基于流实现的,以字节为单位处理数据。三)、NIO的特性1).为所有的原始... 查看详情

nio代码实现简易多人聊天(代码片段)

这几天在学习nio相关知识。实现了一个简单的多人聊天程序。服务端代码;1importjava.io.IOException;2importjava.net.InetSocketAddress;3importjava.nio.ByteBuffer;4importjava.nio.channels.*;5importjava.nio.charset.Charset;6importjava.util.* 查看详情

javaio/nio的基本概念学习(代码片段)

一、IO模型阻塞IO模型最传统的IO模型,即在读写数据过程中会发生阻塞现象(可以理解为等待)。当用户线程发出IO请求之后,内核会去查看数据是否就绪,若为就绪,用户线程则处于阻塞状态,并交... 查看详情

aio异步非阻塞学习(代码片段)

 Client:客户端packageaio;importjava.io.UnsupportedEncodingException;importjava.net.InetSocketAddress;importjava.nio.ByteBuffer;importjava.nio.channels.AsynchronousSocketChannel;importjava.util.concu 查看详情

netty学习(源码分析)(代码片段)

源代码目录JavaIO到NettyNIO基础NIO的特点NIO怎么实现的同步非阻塞JavaBIO与NIO比较BIO(传统IO)伪异步IO模式NIO(Non-blocking/NewI/O)BIO和NIO对比AIO模式文件AIO网络通信AIOBIO、NIO和AIO区别零拷贝传统IO的问题NIO的优化sendFilel... 查看详情

nio原理和示例代码(代码片段)

我正在为学习大数据打基础中,为了手撸rpc框架,需要懂得nio的原理,在搞懂nio框架前,我会带着大家手撸一些比较底层的代码,当然今后当我们学会了框架,这些繁琐的代码也就不用写了,但是学一学底层的代码也是有好处的... 查看详情

nio学习(代码片段)

1.NIO客户端与服务端网络编程关键:理解各个监听事件的驱动事件,总结以下几点:(1)ServerSocketChannel注册了OP_ACCEPT事件,需要客户端发起连接请求,服务端selector才能监听到(阻塞在selector.select()才能继续执行)(2)服务端获... 查看详情

nio-filechannel源码分析(代码片段)

...NIO-SocketChannel源码分析NIO-FileChannel源码分析前言本来是想学习Netty的,但是Netty是一个NIO框架,因此在学习netty之前,还是先梳理一下NIO的知识。通过剖析源码理解NIO的设计原理。本系列文章针对的是JDK1.8.0.161的源码。上一篇对Sock... 查看详情

netty学习笔记四了解缓冲区(代码片段)

了解缓冲区NIO核心对象1.Buffer简介2.一段简单的Buffer使用例子3.Buffer的重要属性positionlimitcapacitymark4.缓冲区的分配5.子缓冲区6.只读缓冲区7.直接缓冲区8.内存映射NIO核心对象在NIO中,缓冲区、选择器、通道是三个核心的对象。... 查看详情

nio-channel接口分析(代码片段)

...录NIO-概览NIO-BufferNIO-ChannelNIO-Channel源码分析前言本来是想学习Netty的,但是Netty是一个NIO框架,因此在学习netty之前,还是先梳理一下NIO的知识。通过剖析源码理解NIO的设计原理。本系列文章针对的是JDK1.8.0.161的源码。上一篇介绍... 查看详情

javanio利用通道完成文件复制(mappedbytebuffer)(代码片段)

相关学习网址:importjava.io.IOException;importjava.nio.MappedByteBuffer;importjava.nio.channels.FileChannel;importjava.nio.channels.FileChannel.MapMode;importjava.nio.file.Paths;importjava.nio.file.StandardO 查看详情

nio-selector(代码片段)

...hannel源码分析NIO-FileChannel源码分析NIO-Selector前言本来是想学习Netty的,但是Netty是一个NIO框架,因此在学习netty之前,还是先梳理一下NIO的知识。通过剖析源码理解NIO的设计原理。本系列文章针对的是JDK1.8.0.161的源码。前几篇文章... 查看详情

nio-channel(代码片段)

...录NIO-概览NIO-BufferNIO-ChannelNIO-Channel源码解析前言本来是想学习Netty的,但是Netty是一个NIO框架,因此在学习netty之前,还是先梳理一下NIO的知识。通过剖析源码理解NIO的设计原理。本系列文章针对的是JDK1.8.0.161的源码。什么是Channe... 查看详情

javanio学习笔记上(尚硅谷)(代码片段)

1、javaNIO概述JavaNIO(NewIO或NonBlockingIO)是从Java1.4版本开始引入的一个新的IOAPI,可以替代标准的JavaIOAPI。NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。1.1阻塞IO通常在进行同... 查看详情

nio(代码片段)

...,io通道面向流.针对网络通信: nio是  一.缓冲区学习 根据源码,查看核心buffer四个属性.缓冲区读写数据原理缓冲区详解packagecom.atguigu.nio;importjava.nio.ByteBuffer;importorg.junit.Test;/**一、缓冲区(Buffer):在JavaNIO中负责数... 查看详情

nio(代码片段)

使用直接缓冲区完成文件的复制(内存映射文件)packagecom.cppdy.nio;importjava.nio.MappedByteBuffer;importjava.nio.channels.FileChannel;importjava.nio.channels.FileChannel.MapMode;importjava.nio.file.Paths;importjava.nio.file 查看详情

nio通道(代码片段)

nio通道的创建方式一:通过IO流创建nio通道packageedzy.nio; 1packageedzy.nio;23importorg.junit.Test;45importjava.io.FileInputStream;6importjava.io.FileOutputStream;7importjava.io.IOException;8importjava.nio.ByteBuf 查看详情