关键词:
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 查看详情