BIO、NIO、Netty演化总结之二(手撸一个极简版netty)

之前的一片文章里面总结了一下IO模型的演进(BIO、NIO、Netty演化总结-CSDN博客),里面给了一个示例AsyncNonBlockingServerWithThreadPool,最近想了想,发现这个代码跟netty的模型还是有一些出入,说是netty的雏形好像有点牵强,于是想了一下,还是决定写一个更接近netty的极简版代码,仅供交流,有不对的地方欢迎指正,不喜勿喷,直接上代码

public class MyBossGroup {//多路复用器private Selector selector;private ServerSocketChannel serverChannel;//读写处理线程(对应netty里面的worker线程组)private MyWorkerGroup[] myWorkerGroups = new MyWorkerGroup[10];//计数器,用于从线程组中挑选一个线程来处理事件private final AtomicLong idx = new AtomicLong();public MyBossGroup(int port) throws IOException {// 创建选择器和服务器通道selector = Selector.open();serverChannel = ServerSocketChannel.open();serverChannel.bind(new InetSocketAddress(port));serverChannel.configureBlocking(false);// 注册服务器通道到选择器,并注册接收连接事件serverChannel.register(selector, SelectionKey.OP_ACCEPT);for (int i = 0; i < myWorkerGroups.length; i++) {myWorkerGroups[i] = new MyWorkerGroup();}}public void start() throws IOException {System.out.println("Server started.");while (true) {// 阻塞等待事件发生selector.select();// 处理连接事件Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();keyIterator.remove();// 接收连接事件handleAccept(key);}}}private void handleAccept(SelectionKey key) throws IOException {ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverChannel.accept();clientChannel.configureBlocking(false);//挑选一个线程,将clientChannel绑定到这个线程中去MyWorkerGroup myWorkerGroup = myWorkerGroups[(int) Math.abs(idx.getAndIncrement() % myWorkerGroups.length)];//已经建立连接的socket交给worker线程组myWorkerGroup.register(clientChannel);System.out.println("New client connected: " + clientChannel.getRemoteAddress());}public static void main(String[] args) {try {MyBossGroup server = new MyBossGroup(8080);server.start();} catch (IOException e) {e.printStackTrace();}}
}

这个MyBossGroup就是我们在编写netty应用程序的时候的bossgroup的核心逻辑,负责接收客户端连接,并且将连接的socket注册到worker线程组中,下面的MyWorkerGroup就是编写netty应用程序的时候的workergroup的核心逻辑,负责数据的读写:

public class MyWorkerGroup {private Selector selector;private Thread thread;private ByteBuffer buffer;public MyWorkerGroup() {try {selector = Selector.open();} catch (IOException e) {e.printStackTrace();}thread = new Thread(new MyRunnable());buffer = ByteBuffer.allocate(1024);}class MyRunnable implements Runnable {@Overridepublic void run() {while (true) {try {int select = selector.select();if (0 == select) {TimeUnit.MILLISECONDS.sleep(10);continue;}// 处理连接事件Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();keyIterator.remove();SocketChannel clientChannel = (SocketChannel) key.channel();if (key.isReadable()) {buffer.clear();int bytesRead = 0;try {bytesRead = clientChannel.read(buffer);} catch (IOException e) {e.printStackTrace();closeSocketChannel(key, clientChannel);continue;}if (bytesRead == -1) {closeSocketChannel(key, clientChannel);try {System.out.println("Client disconnected: " + clientChannel.getRemoteAddress());} catch (IOException e) {e.printStackTrace();}continue;}buffer.flip();byte[] data = new byte[buffer.remaining()];buffer.get(data);System.out.println("Received message from client: " + new String(data));System.err.println("current_thread:" + Thread.currentThread().getName());} else {closeSocketChannel(key, clientChannel);}}} catch (Exception e) {e.printStackTrace();}}}private void closeSocketChannel(SelectionKey key, SocketChannel socketChannel) {try {System.out.println("Client disconnected: " + socketChannel.getRemoteAddress());// 客户端关闭连接key.cancel();socketChannel.close();} catch (IOException e) {e.printStackTrace();}}}public void register(SocketChannel socketChannel) {try {socketChannel.register(selector, SelectionKey.OP_READ);} catch (ClosedChannelException e) {e.printStackTrace();}thread.start();}
}

可以看到两个group其核心逻辑都是一个死循环,监听selector里面的事件,只是在netty里面将这两个死循环合并到了一个类里面,也就是NioEventLoop的run方法,每一个NioEventLoop独立维护一个自己的selector和任务队列(在这里没有体现),客户端连接第一次连接过来的socket绑定到一个NioEventLoop之后,后面这个socket的读写事件就全部由这个NioEventLoop负责,这样就有几个好处:

1、selector.select是一个阻塞的方法,由于每一个workergroup独立维护自己的selector,不会相互影响

2、每一个连接的客户端在绑定workergroup的时候实际上就是绑定了一个selector,这样每一个workergroup所负责管理的客户端连接的socket之间也相互不影响

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

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

相关文章

【MATLAB】BiGRU神经网络回归预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 BiGRU神经网络回归预测算法是一种基于双向门控循环单元&#xff08;GRU&#xff09;的多变量时间序列预测方法。该方法结合了双向模型和门控机制&#xff0c;旨在有效地捕捉时间序列数据中…

【设计模式】详细聊聊软件设计的七大原则

软件设计原则 软件设计原则是指在进行软件系统设计时所遵循的一系列指导原则&#xff0c;它们旨在帮助软件工程师设计出高质量、易维护、可扩展和可重用的软件系统。这些原则是经过实践验证的&#xff0c;能够在软件开发的各个阶段提供指导和支持。七大软件设计原则&#xff0c…

高级前端面试题及详解

当准备高级前端面试时&#xff0c;除了掌握基本的前端知识外&#xff0c;还需要深入了解一些更高级的概念和技术。以下是一些常见的高级前端面试题及其详解&#xff0c;希望能帮助你更好地准备面试。 什么是闭包&#xff1f;请举一个闭包的例子并解释其工作原理。 闭包是指函数…

如何利用Idea创建一个Servlet项目(新手向)

&#x1f495;"Echo"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;如何利用Idea创建一个Servlet项目(新手向) Servlet是tomcat的api,利用Servlet进行webapp开发很方便,本文将介绍如何通过Idea创建一个Servlet项目(一共分为七步,这可能是我们写过的…

Kotlin函数和对象

1.高阶函数 如果一个函数的参数是函数类型或者返回值是函数类型&#xff0c;那么这个函数就是高阶函数。 在kotlin中函数也是有类型的&#xff0c;跟整型、字符串类型是同样的性质&#xff0c;函数类型就是将函数的“输入参数类型”和“返回值类型”的抽象表达&#xff0c;如&…

C#使用MiniExcel导入导出数据到Excel/CSV文件

MiniExcel简介 简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。 目前主流框架大多需要将数据全载入到内存方便操作&#xff0c;但这会导致内存消耗问题&#xff0c;MiniExcel 尝试以 Stream 角度写底层算法逻辑&#xff0c;能让原本1000多MB占用降低到几MB&#xff…

论文阅读,ProtoGen: Automatically Generating Directory Cache Coherence Protocols(三)

目录 一、Article:文献出处&#xff08;方便再次搜索&#xff09; &#xff08;1&#xff09;作者 &#xff08;2&#xff09;文献题目 &#xff08;3&#xff09;文献时间 &#xff08;4&#xff09;引用 二、Data:文献数据&#xff08;总结归纳&#xff0c;方便理解&am…

扫地机器人与项目管理

最近家里新装了一台扫地机器人&#xff0c;可以远程操控&#xff0c;每次回家前&#xff0c;都让它扫拖一遍&#xff0c;非常的干净。家里东西摆放比较杂乱&#xff0c;每次它要清理的面积都是一个不规则图形。通过几次的观察&#xff0c;发现它总是把要清理的区域先整个画一个…

1057:简单计算器

题目描述】 一个最简单的计算器&#xff0c;支持, -, *, / 四种运算。仅需考虑输入输出为整数的情况&#xff0c;数据和运算结果不会超过int表示的范围。然而&#xff1a; 1. 如果出现除数为0的情况&#xff0c;则输出&#xff1a;Divided by zero! 2. 如果出现无效的操作符(即…

TCP如何保证传输可靠性?

文章目录 前言1、连接管理1.1、三次握手1.2、四次挥手 2、校验和3、序列号 确认应答4、重传机制4.1、超时重传4.2、快速重传 5、流量控制5.1、累计应答5.2、滑动窗口 6、拥塞控制6.1、慢启动6.2、拥塞避免6.3、拥塞发生6.4、快速恢复 前言 文章参考&#xff1a; 《网络是怎样…

「年后复工主题」app用户运营拉新,接入引爆用户增长的活动

随着春节假期的结束&#xff0c;人们重返工作岗位&#xff0c;各行各业也迎来了年后复工的高峰期。在这个时间节点&#xff0c;APP运营团队面临着一个绝佳的机遇——利用节日余温和复工活力&#xff0c;通过策划一系列相关主题的趣味活动来吸引新用户&#xff0c;实现用户增长的…

文件上传漏洞--Upload-labs--Pass06--空格绕过

一、什么是空格绕过 在Windows系统中&#xff0c;Windows特性会自动删除文件后缀名后的空格&#xff0c;这使我们看 .php 和 .php 二者没有任何区别&#xff0c;实际上二者是有区别的。若网页源码没有使用 trim()函数 来进行去除空格的操作&#xff0c;就会使网页存在 空格绕…

什么样的服务器是高性能服务器?

首先&#xff0c;高性能服务器应具备高处理能力。随着业务的不断扩展和数据量的爆炸性增长&#xff0c;高性能服务器需要具备强大的计算能力&#xff0c;能够快速处理各种复杂的业务和数据。这要求高性能服务器采用先进的处理器技术&#xff0c;如多核处理器、GPU加速等&#x…

IDEA中创建web项目(配置tomcat,tomcat启动报程序包javax.servlet.http不存在,tomcat控制台乱码问题)

文章目录 一、新建动态web项目1、新建项目2、选择创建动态web项目3、项目命名4、编辑index.jsp 二、配置Tomcat1、新增tomcat服务器配置2、选择服务器类型3、配置服务器参数4、部署项目5、完成配置6、启动运行7、访问web项目 三、tomcat启动报程序包javax.servlet.http不存在四…

个人简历补充

个人简历补充 1.对工作的认识2.八股文和知识面3.框架/架构角度深扒3.1 前端3.1.1 mPaaS&#xff08;移动领域&#xff09;3.1.2 普通前端项目框架3.1.3 微前端 3.2 后端 持续更新 1.对工作的认识 2.八股文和知识面 前端&#xff08;基础知识 / 开发能力 / 总结输出能力&#xf…

vue-productionSourceMap作用

当其设置为false时(productionSourceMap: false) 当其设置为true时(productionSourceMap: true) 注:1.当设置为true时,打包后每个文件都有一个.map文件,其目的是为了精确定位代码错误 2.当设置为false时,可减少项目打包大小 3.正式环境禁止使用true,因为其可通过反编译.map文件…

HCIA-HarmonyOS设备开发认证V2.0-IOT硬件子系统-UART

目录 一、UART 概述二、UART 模块相关API三、UART 接口调用实例四、UART HDF驱动开发4.1、开发步骤(待续...) 坚持就有收获 一、UART 概述 UART 是通用异步收发传输器&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09;的缩写&#xff0c;是通用串行数据总…

调用百度文心AI作画API实现中文-图像跨模态生成

作者介绍 乔冠华&#xff0c;女&#xff0c;西安工程大学电子信息学院&#xff0c;2020级硕士研究生&#xff0c;张宏伟人工智能课题组。 研究方向&#xff1a;机器视觉与人工智能。 电子邮件&#xff1a;1078914066qq.com 一&#xff0e;文心AI作画API介绍 1. 文心AI作画 文…

上传(图片)文件的功能实现

说句实话&#xff0c;现在的开发简单多了。因为有现成的第三方的上传文件的代码。如果放在我们以前做开发&#xff0c;上传文件的代码都得自己写。 那现在的程序员面对上传文件的功能到底写啥代码。 1&#xff09;、对于前端人员&#xff1a;就是把后端的请求地址&#xff0c…

阿基米德签证小程序管理系统功能清单

阿基米德签证小程序管理系统&#xff0c;底层架构采用当前国内最流行的php框架thinkphp8.0、采用广泛使用的MYSQL数据库&#xff0c;管理后台前后台分离&#xff0c;同时使用了当今最流行的基于VUE3和elementPlus前端框架&#xff0c;小程序采用了支持多端合一的UNI-APP开发&am…