学习完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都需要自己研究的,不过这是个漫长的过程吧,以自己的惰性来看: 不过开发中不是有时候讲究模块化开发么,那么我 ...
随机推荐
- 不是吧?30秒 就能学会一个python小技巧?!
大家好鸭!我是小熊猫 很多学习Python的朋友在项目实战中会遇到不少功能实现上的问题,有些问题并不是很难的问题,或者已经有了很好的方法来解决.当然,孰能生巧,当我们代码熟练了,自然就能总结一些好用的 ...
- 水电表/燃气表/压力表/传感器/仪器仪表等,超低功耗段码LCD液晶显示驱动IC-VKL144A/B 超低工作电流,36*4COM显示,替代PCF8551/MCP144/BU9792/9B92/BL55072B等
煤气罐的使用安全隐患较大,现在大部分城市使用管道输送燃气,燃气表的计费大都是通过远程抄表的方式,或者充值的方式,为了让用户更好地了解自家燃气表的使用情况,需要一款液晶屏来显示燃气表的状态和用气量等信息 ...
- 只会Excel想做图表可视化,让数据动起来?可以,快来围观啦(附大量模板下载)
前言 之前我们分享过基于echarts 的数据可视化展示,很多朋友就说,不会软件开发,可不可以直接用Excel进行数据化的展示. 答案是肯定的,确实有这种方案,百度查询一查一大推,各种解决方案各种模板 ...
- 2500-使用MyBatis操作MySQL进行批量更新的注意事项
原则上一条SQL只更新一条数据库操作,但有时需要批量操作数据,特别是一些DML语句,在操作数据库时,数据库会报出异常,不允许混合语句,此时需要额外配置进行兼容. 例如: Caused by: com. ...
- Postgres常用时间查询
如select extract(day from now());
- git diff与linux diff的输出格式之unified format
前言 前面有一篇文章<一个有些意思的项目--文件夹对比工具(一)>,里面简单讲了下diff算法之--Myers算法. 既然是算法,就会有实现,比如git diff中有Myers的实现,gi ...
- ROS机械臂 Movelt 学习笔记4 | Move Group 接口 Python
Python 的使用总是比 C++ 简单许多,Move Group 的 Python 接口更为便捷,也为使用者提供了很多用于操纵机器人和机械臂的函数,能够和 C++ 接口实现相同的功能: 设置机械臂的 ...
- 蔚来杯2022牛客暑期多校训练营6 ABGJM
比赛链接 A 题解 知识点:数学,构造. 题目要求构造一个长为 \(m\) 的序列 \(c\) ,\(m\) 自选,使得 \(c\) 的无限循环序列 \(b\) 中任意连续 \(a_i\) 个数中都存 ...
- DolphinScheduler & K8s 在优路科技的实践
T 摘要 · 本文通过介绍DolphinScheduler on Kubernetes 在优路科技的实践,阐述了DolphinScheduler如何在云原生时代,更好地助力企业实现高效的数据调度解决方 ...
- Oracle-查询之函数
DQL语句:查询语句用于查询表中数据DQL必须包含的两个部分:select 子句 和from 子句select子句:指定要查询的内容,可以指定表中的具体字段,*号,函数,或者表达式from子句:指定数 ...