学习完nio的一个小笔记吧
- 这是一个nio网络通信服务端的demo,主要就学习了selector的一些用法,以及它里面的事件类型
- selector是对nio的一个优化,它能保证既能高效处理线程中的事件,又能保证线程不会一直占用cpu
其中我认为最重要的是selector的执行流程,机制
将 channel和 selector建立联系。(联系就是指客户端向服务端发送的某个事件会被selector给监听到)。
当客户端给服务器发送了相应事件后,selector就会将这个事件的 selectionKey加入到集合 selectionKeys中,并且处理该事件。
在处理事件的时候,可以根据事件类型来进行处理。比如说使用 channel.accept()、channel.read(xx)来处理。
对一些客户端异常关闭,或者说正常关闭要特殊处理。客户端关闭,可以直接调 key.cancel()将该key从 selector中删除。
服务端
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import static com.pzistart.utils.ByteBufferUtil.debugRead;
/**
* @author Pzi
* @create 2022-09-12 17:47
*/
@Slf4j
public class ServerUp {
public static void main(String[] args) throws IOException {
ServerSocketChannel ssc = ServerSocketChannel
.open()
.bind(new InetSocketAddress(8080));
// 1.创建 selector,管理多个 channel
Selector selector = Selector.open();
// 2.开启非阻塞模式,并且将ssc注册到selector中
ssc.configureBlocking(false);
// 3.建立 ssc(channel) 和 selector 的联系
SelectionKey sscKey = ssc.register(selector, SelectionKey.OP_ACCEPT);
log.debug("regist key:{}", sscKey);
while (true) {
// 如果selector监听到有事件发生,那么就向 selectionKeys 这个集合中加入key。
// 并且执行下面的操作,否则就阻塞线程
int count = selector.select();
// selectionKeys中包含所有的事件
Set<SelectionKey> selectionKeys = selector.selectedKeys();
// 4.处理事件
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
// 在selectionKeys中即使是处理完毕事件,也不会自动移除key。
// 导致下一次处理事件的时候,还会找到事件类型为 accept 的那个 SelectionKey
// 但是由于accept事件已经被消耗,所以获取不到对应的 ServerSocketChannel。所以在用完该key,就要立马移除集合中该key
iterator.remove();
// 如果客户端发过来的是 accept相关的事件,那么就会被 selector 识别并且将该时间加入到 selectionKeys集合中。从而在下面的事件处理分支进行处理。
// 如果客户端发过来的是 read相关的之间,同样的事件处理方式
if (key.isAcceptable()) {
log.debug("key{}", key);
ServerSocketChannel c = (ServerSocketChannel) key.channel();
// 调用accept()方法处理事件
SocketChannel sc = c.accept();
sc.configureBlocking(false);
// 将sc注册到selector中,建立sc(channel)和selector的联系
SelectionKey scKey = sc.register(selector, SelectionKey.OP_READ);
log.debug("connected... {}", sc);
// 也可以调用cancel()方法处理事件 key.cancel();
} else if (key.isReadable()) {
try {
SocketChannel channel = (SocketChannel) key.channel();
// 将sc注册到selector中
ByteBuffer buffer = ByteBuffer.allocate(16);
int read = channel.read(buffer);
if (read == -1) {
key.cancel();
} else {
buffer.flip();
debugRead(buffer);
buffer.clear();
}
} catch (Exception e) {
e.printStackTrace();
// 在客户端异常断开连接时,客户端会向服务器发送一个 read()事件
// read()事件没有得到处理,那么就会多次被 selector监听到,从而循环抛异常。
// 解决方法就是将该 key删除,就是直接从 selector中反注册,那么 selector自然不会监听到该 channel的相应事件
// key.cancel();
}
}
}
}
}
}
客户端
package com.pzistart.netcoding.bio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;
/**
* @author Pzi
* @create 2022-09-12 15:04
*/
public class Client {
public static void main(String[] args) throws IOException {
SocketChannel sc = SocketChannel.open();
sc.connect(new InetSocketAddress("localhost", 8080));
System.out.println("ccc");
}
}
学习完nio的一个小笔记吧的更多相关文章
- 一个小笔记(8):EN_2
Why is programming fun? What delights may its practitioner expect as his reward? First is the sheer ...
- 一个小笔记(7):EN_1
For nearly ten years, the Unified Modeling Language(UML) has been the industry standard for visualiz ...
- 一个小笔记(2):Socket网络编程
网络通信的流程: 服务器端申请套接字 -> 绑定套接字到本地,打开端口 -> 监听端口 -> 等待接受消息 -> 有消息之后,读取消息 客户端申请套接字 -> 向服务端发 ...
- 一个小笔记(5):A*算法
A-Star算法是一种静态路网中求解最短路径最有效的直接搜索方法其实百科有 http://baike.baidu.com/link?url=CvmkWQIAmztYgMq3Nk1WyWkDiC0koV ...
- JavaScript关于返回数据类型一个小小的笔记
Javascript关于返回数据类型的一个小笔记 javascript数据类型有两种. 一种是基本数据类型:String.Number.Boolean.Symbol.Underfine.Null 一种 ...
- c++学习笔记---04---从另一个小程序接着说
从另一个小程序接着说 文件I/O 前边我们已经给大家简单介绍和演示过C和C++在终端I/O处理上的异同点. 现在我们接着来研究文件I/O. 编程任务:编写一个文件复制程序,功能实现将一个文件复制到另一 ...
- c++学习笔记---03---从一个小程序说起2
从一个小程序说起2 要求:编写一个程序,要求用户输入一串整数和任意数目的空格,这些整数必须位于同一行中,但允许出现在该行中的任何位置.当用户按下键盘上的"Enter"键时,数据输入 ...
- c++学习笔记---02---从一个小程序说起
从一个小程序说起 这一讲的主要目的是帮助大家在C语言的背景知识上与C++建立联系. 问题探索 问题:对一个整型数组求和. 要求:定义一个存储着 n 个元素的数组,要求用C语言完成这个任务. 赶紧的:大 ...
- java8 学习系列--NIO学习笔记
近期有点时间,决定学习下java8相关的内容: 当然了不止java8中新增的功能点,整个JDK都需要自己研究的,不过这是个漫长的过程吧,以自己的惰性来看: 不过开发中不是有时候讲究模块化开发么,那么我 ...
随机推荐
- halcon 基础总结(一)裁切图片并旋转图像
第一步当然是读取图像了:read_image (Image, 'C:/Users/HJ/Desktop/test_image/b.jpg') 第二步:二值化.二值化.因为我这里的物体是黑色的, ...
- Tapdata 实时数据融合平台解决方案(四):技术选型
作者介绍:TJ,唐建法,Tapdata 钛铂数据CTO,MongoDB中文社区主席,原MongoDB大中华区首席架构师,极客时间MongoDB视频课程讲师. 常见搭建数据中台的技术产品 数据中台包括: ...
- 【RocketMQ】消息的拉取
RocketMQ消息的消费以组为单位,有两种消费模式: 广播模式:同一个消息队列可以分配给组内的每个消费者,每条消息可以被组内的消费者进行消费. 集群模式:同一个消费组下,一个消息队列同一时间只能分配 ...
- 低代码如何构建支持OAuth2.0的后端Web API
OAuth2.0 OAuth 是一个安全协议,用于保护全球范围内大量且不断增长的Web API.它用于连接不同的网站,还支持原生应用和移动应用于云服务之间的连接,同时它也是各个领域标准协议中的安全层. ...
- 查询postgresql表结构和索引
通过系统数据字典查询表结构 selectcol.table_schema,col.table_name,col.ordinal_position,col.column_name,col.data_ty ...
- osi七层与TCP\IP协议
层次划分的方法 1.网络的每层应当具有相对独立的功能(便于排错)这个功能用不了必然是你这层处理问题 2.梳理功能之间的关系,使上一个功能可以实现为另一个功能提供必要的服务,从而形成系统的层次结构.为提 ...
- Kubernetes v1.24 基于containerd部署
k8s每个节点安装containerd. containerd安装参考<containerd安装博文>:https://www.cnblogs.com/punchlinux/p/1 ...
- jdbc 03:注册驱动的方式
jdbc连接mysql时,注册驱动的方式 package com.examples.jdbc.o3_注册驱动方式; //mysql驱动所在的包 import com.mysql.jdbc.Driver ...
- PHP几个工具函数
移除XSS攻击脚本 function RemoveXSS($val) { // remove all non-printable characters. CR(0a) and LF(0b) and T ...
- 基于Sikuli GUI图像识别框架的PC客户端自动化测试实践
写在前面 最近两天,公司有个PC客户端的测试任务,除了最基础的功能测试外,还包括稳定性测试和兼容性测试需求.刚好去年接触过Sikuli这款基于GUI图像识别框架的自动化测试工具,于是便应用于测试工作中 ...