【网络编程(二)】NIO快速入门

NIO

Java NIO 三大核心组件

  1. Buffer(缓冲区):每个客户端连接都会对应一个Buffer,读写数据通过缓冲区读写。
  2. Channel(通道):每个channel用于连接Buffer和Selector,通道可以进行双向读写。
  3. Selector(选择器):一个选择器对应多个通道,用于监听多个通道的事件。Selector可以监听所有的channel是否有数据要读取,当某个channel有数据时,就去处理,所有channel都没有数据时,线程可以去执行其他任务。

image-20210916114642170

使用 NIO 模型操作 Socket 步骤:

  1. 创建 ServerSocketChannel 服务器;
  2. 创建多路复用器 Selector(每个操作系统创建出来的是不一样的 ,Windows创建的是 WindowsSelectorImpl)
  3. ServerSocketChannel 将建立连接事件注册到 Selector中(register 方法往 EPollArrayWrapper 中添加元素)
  4. 处理事件
    1. 如果是建立连接事件,则把客户端的读写请求也注册到Selector中;
    2. 如果是读写事件则按业务处理。

案例代码:

public class NioServer {public static void main(String[] args) throws IOException {// 创建服务器ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8888));serverSocketChannel.configureBlocking(false); // 配置成非阻塞式的channel// 创建一个IO多路复用选择器Selector selector = Selector.open();// 注册serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {// 阻塞的方法,返回值代表发生事件的通道的个数// 返回值 0 超时// -1 错误// select方法可以传递超时时间,如果不传的话是timeout最后会为-1表示不会超时selector.select();// 如果不设的话客户端不操作会一直阻塞在这// 只要走到这里,必然说明,发送了事情,有可读可写可连接的channelSet<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();// 这个事件处理完就删除if (selectionKey.isAcceptable()) {// 有客户端来连接了// 三次握手建立连接SocketChannel socketChannel = serverSocketChannel.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));System.out.println("某某客户端连接来啦");}if (selectionKey.isReadable()) {SocketChannel socketChannel = (SocketChannel) selectionKey.channel();ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();buffer.clear();int read = socketChannel.read(buffer);if (read == -1) { // 如果是可读事件,然后又没有数据,说明是客户端与服务器端的连接断开了,// 这个时候我们关闭通道,不然选择器会一直监听通道,导致不必要的业务执行socketChannel.close();} else {System.out.println(new String(buffer.array(), 0, buffer.position()));System.out.println("有信息需要读取");}}iterator.remove();}}}
}

doSelect 方法是由 WindowsSelectorImpl 类去实现的,这是select方法最后执行的方法,因为加了互斥锁,也是为什么说这里同步阻塞的原因。
在这里插入图片描述

俩问题:

  • 当 Selector.select() 方法返回后,它会返回一组 SelectionKey 对象,这些对象代表了已经就绪的 I/O 通道,即对应的文件描述符上有事件发生。这些 SelectionKey 对象Key用来处理对应的事件。但是,如果不将已经处理过的 SelectionKey 对象从 Selector 中删除,下次调用 Selector.select() 方法时,这些已经处理过的 SelectionKey 对象扔然会被返回,导致多余的事件处理,影响性能问题。

  • 删除的话,我们可以通过 SelectionKey.cancel() 方法来实现,并且使得对应的通道(即文件描述符)不再被Selector监视。(这是有问题的,这样的话以后这个 SelectionKey 就不会再被监听了)可以在迭代器使用的时候对其进行删除。

Netty 封装好后就帮我们解决了这种问题,不会出现事件处理完后续还会一直处理的现象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/68413.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django-配置邮箱功能(一):使用django自带的发送邮件功能

一、获取邮箱授权码 以QQ邮箱为例子&#xff1a; 1、进入到设置&#xff0c;找到账户 2、开启POP3等服务&#xff0c;点击管理服务 3、进入管理服务&#xff0c;生成授权码 4、按照要求发送短信就可以了 5、将授权码复制保存&#xff0c;离开界面就看不到了 二、django项目中…

【Vue】Vue2创建移动端项目实战教程,创建移动端项目保姆级教程,设置axios,utils工具包,vue.fonfig.js配置项 (下)

系列文章目录 这里是创建移动端项目 【Vue】Vue2.x创建项目全程讲解&#xff0c;保姆级教程&#xff0c;手把手教&#xff0c;Vue2怎么创建项目&#xff08;上&#xff09; 【Vue】Vue2创建移动端项目实战教程&#xff0c;创建移动端项目保姆级教程&#xff0c;接上一篇创建Vue…

无法解析的外部符号cusolverDnCreate

问题&#xff1a; 无法解析的外部符号cusolverDnCreate 解决方案 那么就在启动项目-》属性-》连接器-》输入-》附加依赖项&#xff1a;加&#xff1a; cublas.lib cublas_device.lib cuda.lib cudadevrt.lib cudart.lib cudart_static.lib cufft.lib cufftw.lib curand.lib …

网盘与相册服务PDS

引言&#xff1a;作为一名开发者&#xff0c;我将通过对PDS&#xff08;Personal/Enterprise Drive System&#xff09;的体验使用&#xff0c;分享一下本人对以下方面的使用体验。 1. 开发个人/企业网盘 功能与应用 PDS作为一种网盘服务中间件产品&#xff0c;为开发者提供了…

Centos7 配置Docker镜像加速器

daemon.json 文档说明&#xff1a; docker安装后默认没有daemon.json这个配置文件&#xff0c;需要进行手动创建&#xff0c;docker不管是在哪个平台以何种方式启动, 默认都会来这里读取配置,使用户可以统一管理不同系统下的 docker daemon 配置。 如果在daemon.json文件中进行…

原子css 和 组件化css如何搭配使用

如果让你来实现下面这种页面&#xff0c;该怎么实现呢 原子化和css组件化方式写法&#xff0c;可以搭配起来使用&#xff0c;常用的css 原子css 比如 下面这些类似flex 布局&#xff0c;lstn curser-pointer 等常用的或者 具备一定规律性的padding margin 样式可以抽取为单独…

Mongodb:业务应用(1)

环境搭建参考&#xff1a;mongodb&#xff1a;环境搭建_Success___的博客-CSDN博客 需求&#xff1a; 在文章搜索服务中实现保存搜索记录到mongdb 并在搜索时查询出mongdb保存的数据 1、安装mongodb依赖 <dependency><groupId>org.springframework.data</groupI…

PHP最简单自定义自己的框架数据库封装调用(五)

1、实现效果调用实现数据增删改查封装 2、创建数据表 CREATE TABLE test (id int(11) NOT NULL AUTO_INCREMENT,name varchar(30) DEFAULT NULL,age int(11) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEMyISAM AUTO_INCREMENT4 DEFAULT CHARSETutf8;3、index.php 入口定义数据库…

UDS (Unified Diagnostic Services)汽车诊断标准协议

参考文献&#xff1a; 《道路车辆统一诊断服务(UDS) Road vehicles - Unified diagnostic services》 1.专业术语 1.TP:Tester Present待机握手 2.支持的诊断故障码&#xff08;DTC&#xff09; supported DTC   当前被配置并且能够在预定义的车辆条件下执行的诊断故障代码…

LeetCode 37题:解数独

题目 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff09; 数独…

vue2中使用mixins(混入)和vue3中使用composable

文章目录 一、mixins混入1、 新建mixins文件夹&#xff0c;新建myMixins.js2、myMixins.js 文件3、index.vue 文件&#xff08;要使用的文件&#xff09; mixins 总结二、composable(组合式api composition )1、 新建composables文件夹&#xff0c;新建useEdit.js2、useEdit.js…

AMS的起源,SystemServer的前世今生

作者&#xff1a;OpenGL 前世 SystemServer的创建还得追溯到之前的Zygote进程中的ZygoteInit代码中。这里的Zygote.forkSystemServer()方法就是实现分裂的关键代码。它内部调用了native方法实现了进程分裂。 执行完这行代码之后。我们的系统中就会出现两个一模一样的进程&…