NIO完成网络通信(一)
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 对象,读取数据。
先启动服务端,不停监听客户端连接
服务端代码
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.ServerSocketChannel;
- import java.nio.channels.SocketChannel;
- import java.util.Iterator;
- public class NIOServer {
- /*标识数字*/
- private int flag = ;
- /*缓冲区大小*/
- private int BLOCK = ;
- /*接受数据缓冲区*/
- private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
- /*发送数据缓冲区*/
- private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
- //选择器
- private Selector selector;
- public NIOServer(int port) throws IOException {
- //1. 获取通道, 打开服务器套接字通道
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
- //2. 切换到非阻塞模式
- serverSocketChannel.configureBlocking(false);
- //3. 绑定连接的端口
- serverSocketChannel.socket().bind(new InetSocketAddress(port));
- //4. 获取选择器
- selector = Selector.open();
- //5. 通道注册到选择器上,指定监听事件:接收。……等待连接
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- System.out.println("Server Start----8888:");
- }
- //监听
- public void listen() throws IOException {
- while(true) {
- //6. 循环获取选择器上已经“准备就绪”的事件,返回的int值表示有多少个通道在上一次select后发生了注册事件
- int nKeys = selector.select();
- if(nKeys>){
- //7. 获取当前选择器中所有注册的选择键(已就绪的监听事件)
- Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
- while(iterator.hasNext()){
- //8. 获取“准备就绪”的事件
- SelectionKey selectionKey = iterator.next();
- //9. 判断具体是什么事件准备就绪,开始处理请求
- handleKey(selectionKey);
- iterator.remove();
- }
- } else {
- try {
- Thread.sleep();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- // 处理请求
- private void handleKey(SelectionKey selectionKey) throws IOException {
- // 接受请求
- ServerSocketChannel server = null;
- SocketChannel client = null;
- String receiveText;
- String sendText;
- int count=;
- // 此选择键的通道是否已准备好接受新的套接字连接。
- if (selectionKey.isAcceptable()) {
- // 返回为之创建此选择键的通道。
- server = (ServerSocketChannel) selectionKey.channel();
- //10. 若“接收就绪”,获取客户端连接
- client = server.accept();
- //11. 切换到非阻塞模式
- client.configureBlocking(false);
- //12. 通道注册到选择器上,指定监听事件:读 就绪
- client.register(selector, SelectionKey.OP_READ);
- } else if (selectionKey.isReadable()) {
- // 返回为之创建此键的通道。
- client = (SocketChannel) selectionKey.channel();
- //将缓冲区清空以备下次读取
- receivebuffer.clear();
- //读取服务器发送来的数据到缓冲区中
- count = client.read(receivebuffer);
- if (count > ) {
- receiveText = new String(receivebuffer.array(),,count);
- System.out.println("服务器端接受客户端数据--:"+receiveText);
- client.register(selector, SelectionKey.OP_WRITE);
- }
- } else if (selectionKey.isWritable()) {
- //将缓冲区清空以备下次写入
- sendbuffer.clear();
- // 返回为之创建此键的通道。
- client = (SocketChannel) selectionKey.channel();
- sendText="message from server--" + flag++;
- //向缓冲区中输入数据
- sendbuffer.put(sendText.getBytes());
- //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
- sendbuffer.flip();
- //输出到通道
- client.write(sendbuffer);
- System.out.println("服务器端向客户端发送数据--:"+sendText);
- client.register(selector, SelectionKey.OP_READ);
- }
- }
- public static void main(String[] args) throws IOException {
- int port = ;
- NIOServer server = new NIOServer(port);
- server.listen();
- }
- }
心得:
1、第5步中,先把服务端通道注册到选择器上,该选择器等待accept接收客户端消息
2、转到第9步,处理请求,如果isAcceptable()=true,准备好接收客户端了,获取客户端连接
3、第12步,客户端通道注册到选择器上,并指定监听读。然后,继续走到listen()方法的循环体中,
4、 这次循环中,上面已获取客户端连接,nKeys >0了,selectionKey 是监听读
5、又到第9步,isReadable()=true,说明是读事件,开始操作数据,通道读取缓冲区
客户端代码
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.SocketChannel;
- import java.util.Iterator;
- import java.util.Set;
- public class NIOClient {
- /*标识数字*/
- private static int flag = ;
- /*缓冲区大小*/
- private static int BLOCK = ;
- /*接受数据缓冲区*/
- private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
- /*发送数据缓冲区*/
- private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
- /*服务器端地址*/
- private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress("127.0.0.1", );
- public static void main(String[] args) throws IOException {
- // TODO Auto-generated method stub
- // 打开socket通道
- SocketChannel socketChannel = SocketChannel.open();
- // 设置为非阻塞方式
- socketChannel.configureBlocking(false);
- // 打开选择器
- Selector selector = Selector.open();
- // 注册连接服务端socket动作
- socketChannel.register(selector, SelectionKey.OP_CONNECT);
- // 连接
- socketChannel.connect(SERVER_ADDRESS);
- // 分配缓冲区大小内存
- Set<SelectionKey> selectionKeys;
- Iterator<SelectionKey> iterator;
- SelectionKey selectionKey;
- SocketChannel client;
- String receiveText;
- String sendText;
- int count=;
- while (true) {
- //选择一组键,其相应的通道已为 I/O 操作准备就绪。
- //此方法执行处于阻塞模式的选择操作。
- selector.select();
- //返回此选择器的已选择键集。
- selectionKeys = selector.selectedKeys();
- //System.out.println(selectionKeys.size());
- iterator = selectionKeys.iterator();
- while (iterator.hasNext()) {
- selectionKey = iterator.next();
- if (selectionKey.isConnectable()) {
- System.out.println("client connect");
- client = (SocketChannel) selectionKey.channel();
- // 判断此通道上是否正在进行连接操作。
- // 完成套接字通道的连接过程。
- if (client.isConnectionPending()) {
- client.finishConnect();
- System.out.println("完成连接!");
- sendbuffer.clear();
- sendbuffer.put("Hello,Server".getBytes());
- sendbuffer.flip();
- client.write(sendbuffer);
- }
- client.register(selector, SelectionKey.OP_READ);
- } else if (selectionKey.isReadable()) {
- client = (SocketChannel) selectionKey.channel();
- //将缓冲区清空以备下次读取
- receivebuffer.clear();
- //读取服务器发送来的数据到缓冲区中
- count=client.read(receivebuffer);
- if(count>){
- receiveText = new String( receivebuffer.array(),,count);
- System.out.println("客户端接受服务器端数据--:"+receiveText);
- client.register(selector, SelectionKey.OP_WRITE);
- }
- } else if (selectionKey.isWritable()) {
- sendbuffer.clear();
- client = (SocketChannel) selectionKey.channel();
- sendText = "message from client--" + (flag++);
- sendbuffer.put(sendText.getBytes());
- //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
- sendbuffer.flip();
- client.write(sendbuffer);
- System.out.println("客户端向服务器端发送数据--:"+sendText);
- client.register(selector, SelectionKey.OP_READ);
- }
- }
- selectionKeys.clear();
- }
- }
- }
运行效果:
NIO完成网络通信(一)的更多相关文章
- JAVA NIO学习三:NIO 的非阻塞式网络通信
紧接着上一章,我们继续来研究NIO,上一章中我们讲了NIO 中最常见的操作即文件通道的操作,但实际上NIO的主要用途还是在于网络通信,那么这个时候就会涉及到选择器,这一章我们就会对其进行讲解操作. 一 ...
- JAVA NIO学习记录2-非阻塞式网络通信
一.阻塞与非阻塞 传统的IO 流都是阻塞式的.也就是说,当一个线程调用read() 或write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务.因此,在完成网络通信 ...
- 4.NIO的非阻塞式网络通信
/*阻塞 和 非阻塞 是对于 网络通信而言的*/ /*原先IO通信在进行一些读写操作 或者 等待 客户机连接 这种,是阻塞的,必须要等到有数据被处理,当前线程才被释放*/ /*NIO 通信 是将这个阻 ...
- NIO 的非阻塞式网络通信
1.阻塞与非阻塞 ① 传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write()时, 该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因 ...
- JDK10都发布了,nio你了解多少?
前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 本来我预想是先来回顾一下传统的IO模式的,将传统的IO模式的相关类理清楚(因为IO的类很多). 但是,发现在整理 ...
- NIO的初步入门
NIO java NIO简介 Java NIO 简介 是从java1.4版本开始引入的一个新的IO AP可以替代标准java IO API NIO与原来的IO有同样的作用和目的,但是使用方式完全不同 ...
- Java之NIO
想要学习Java的Socket通信,首先要学习Java的IO和NIO基础,这方面可以阅读<Java NIO 系列教程>. 下面展示自己代码熟悉Java的NIO编程的笔记. 1.缓冲区(Bu ...
- Java NIO -- 阻塞和非阻塞
传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务.因此,在完成网络通信进行 IO操作 ...
- Java中的NIO及IO
1.概述 Java NIO(New IO) 是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同, ...
随机推荐
- servlet容器、IOC容器、SpirngMVC
servlet容器(这里指tomcat插件)存放servlet对象,而SpringMVC框架整个是一个servlet对象,而IOC容器 在Boot框架中,会存放产生servlet容器的工厂,工厂依据主 ...
- C# 读取word2003 并且显示在界面上的方法
1.新建一个windows窗体程序 2. 引入包WinWordControl.dll 3.添加引用 4.引入组件WinWordControl组件 5.主界面上加入按钮 ,opendialog, win ...
- vSphere 扩展硬盘空间
把所有的snapshot都删除了之后,ssh上去之后,进vmfs目录到client machine的目录. 然后执行下面的方法. 虽然成功了,却没看到有扩展的. 唯一的好处是, vSphone Cli ...
- Virtualbox主机和虚拟机之间文件夹共享及双向拷贝
把文件发到VirtualBox的方法有很多,下面推荐两种: 1.把要共享的文件夹挂载到虚拟机某一个文件上: (1)打开虚拟机的设置,点击左边的“共享文件夹”,点击带加号的文件按钮,在文件夹路径选择要共 ...
- LeetCode--443--压缩字符串(未看)
问题描述: 给定一组字符,使用原地算法将其压缩. 压缩后的长度必须始终小于或等于原数组长度. 数组的每个元素应该是长度为1 的字符(不是 int 整数类型). 在完成原地修改输入数组后,返回数组的新长 ...
- canvas学习之饼状图
接着上一节说,这次我使用canvas绘制了饼状图,主要是SectorGraph.js, 引入 import {canvasPoint} from '../../assets/js/canvas';im ...
- Hadoop/HBase Capacity Planning
http://blog.cloudera.com/blog/2010/08/hadoophbase-capacity-planning/
- android-------- 多渠道打包(借助友盟移动统计分析)
好久没有发博客了,原因是换工作了,今天端午假期,所以来发一篇博客, 多渠道打包,借助友盟移动统计分析,希望对各位有所帮助 多渠道打包的理解: 渠道包就是要在安装包中添加渠道信息,也就是channel, ...
- Android--------WebView+H5开发仿美团 预加载,加载失败和重新加载
Android嵌入式开发已经占大多数了,很多界面都是以网页的形式展示,WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. 本博客主要是模仿美团的旅游出行模块的预加载,网页加载失 ...
- python记录_day22 序列化
序列化是指把内存里的数据类型转换成字符串,以使其能存储到硬盘或通过网络传输到远程,因为硬盘和网络传输时只能接受bytes 一.pickle 把python对象写入到文件中的一种解决方案,但是写入到文件 ...