手撕netty源码(一)- NioEventLoopGroup

文章目录

  • 前言
  • 一、NIO 与 netty
  • 二、NioEventLoopGroup 对象的创建过程
    • 2.1 创建流程图


前言

本文是手撕netty源码系列的开篇文章,会先介绍一下netty对NIO关键代码的封装位置,主要介绍 NioEventLoopGroup 对象的创建过程,看看new一个对象可以做哪些事情。


一、NIO 与 netty

平时使用NIO的主要步骤:

/*创建选择器的实例*/
Selector selector = Selector.open();
/*创建ServerSocketChannel的实例*/
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();/*设置通道为非阻塞模式*/
serverSocketChannel.configureBlocking(false);
/*绑定端口*/
serverSocketChannel.socket().bind(new InetSocketAddress(port));
/*注册事件,表示关心客户端连接*/
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
while(true){/*获取当前有哪些事件*/selector.select(1000);/*获取事件的集合*/Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while(iterator.hasNext()){SelectionKey key = iterator.next();/*我们必须首先将处理过的 SelectionKey 从选定的键集合中删除。如果我们没有删除处理过的键,那么它仍然会在主集合中以一个激活的键出现,这会导致我们尝试再次处理它。*/iterator.remove();handleInput(key);}
}/*处理事件的发生*/
private void handleInput(SelectionKey key) throws IOException {if(key.isValid()){/*处理新接入的客户端的请求*/if(key.isAcceptable()){/*获取关心当前事件的Channel*/ServerSocketChannel ssc= (ServerSocketChannel) key.channel();/*接受连接*/SocketChannel sc = ssc.accept();System.out.println("==========建立连接=========");sc.configureBlocking(false);/*关注读事件*/sc.register(selector,SelectionKey.OP_READ);}/*处理对端的发送的数据*/if(key.isReadable()){SocketChannel sc = (SocketChannel) key.channel();/*创建ByteBuffer,开辟一个缓冲区*/ByteBuffer buffer = ByteBuffer.allocate(1024);/*从通道里读取数据,然后写入buffer*/int readBytes = sc.read(buffer);if(readBytes>0){/*将缓冲区当前的limit设置为position,position=0,用于后续对缓冲区的读取操作*/buffer.flip();/*根据缓冲区可读字节数创建字节数组*/byte[] bytes = new byte[buffer.remaining()];/*将缓冲区可读字节数组复制到新建的数组中*/buffer.get(bytes);String message = new String(bytes,"UTF-8");System.out.println("服务器收到消息:"+message);/*处理数据*/String result = Const.response(message);、、、、、}else if(readBytes<0){/*取消特定的注册关系*/key.cancel();/*关闭通道*/sc.close();}}、、、、}}

平时使用netty的主要步骤:

// 配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ServerInit());// 绑定端口,同步等待成功
b.bind(NettyConstant.SERVER_PORT).sync();

那么,netty 对 NIO 的封装具体体现在哪里呢?先揭晓答案,后续一点点细嚼慢咽

  1. 创建选择器的实例
    io/netty/channel/nio/NioEventLoop.java
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,EventLoopTaskQueueFactory taskQueueFactory, EventLoopTaskQueueFactory tailTaskQueueFactory) {super(parent, executor, false, newTaskQueue(taskQueueFactory), newTaskQueue(tailTaskQueueFactory),rejectedExecutionHandler);this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");final SelectorTuple selectorTuple = openSelector();this.selector = selectorTuple.selector;this.unwrappedSelector = selectorTuple.unwrappedSelector;
}
  1. 创建ServerSocketChannel的实例
    io/netty/channel/socket/nio/NioServerSocketChannel.java
private static ServerSocketChannel newChannel(SelectorProvider provider, InternetProtocolFamily family) {try {ServerSocketChannel channel =SelectorProviderUtil.newChannel(OPEN_SERVER_SOCKET_CHANNEL_WITH_FAMILY, provider, family);return channel == null ? provider.openServerSocketChannel() : channel;} catch (IOException e) {throw new ChannelException("Failed to open a socket.", e);}
}
  1. 设置通道为非阻塞模式
    io/netty/channel/nio/AbstractNioChannel.java
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {super(parent);this.ch = ch;this.readInterestOp = readInterestOp;try {ch.configureBlocking(false);} catch (IOException e) {try {ch.close();} catch (IOException e2) {logger.warn("Failed to close a partially initialized socket.", e2);}throw new ChannelException("Failed to enter non-blocking mode.", e);}}
  1. 绑定端口
    io/netty/bootstrap/AbstractBootstrap.java
private static void doBind0(final ChannelFuture regFuture, final Channel channel,final SocketAddress localAddress, final ChannelPromise promise) {// This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up// the pipeline in its channelRegistered() implementation.channel.eventLoop().execute(new Runnable() {@Overridepublic void run() {if (regFuture.isSuccess()) {channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);} else {promise.setFailure(regFuture.cause());}}});}
  1. 注册事件,表示关心客户端连接
    io/netty/channel/nio/AbstractNioChannel.java
protected void doRegister() throws Exception {boolean selected = false;for (;;) {try {selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);return;} catch (CancelledKeyException e) {if (!selected) {// Force the Selector to select now as the "canceled" SelectionKey may still be// cached and not removed because no Select.select(..) operation was called yet.eventLoop().selectNow();selected = true;} else {// We forced a select operation on the selector before but the SelectionKey is still cached// for whatever reason. JDK bug ?throw e;}}}}
  1. 获取当前事件的集合
  2. 处理事件
    io/netty/channel/nio/NioEventLoop.java
private int select(long deadlineNanos) throws IOException {if (deadlineNanos == NONE) {return selector.select();}// Timeout will only be 0 if deadline is within 5 microsecslong timeoutMillis = deadlineToDelayNanos(deadlineNanos + 995000L) / 1000000L;return timeoutMillis <= 0 ? selector.selectNow() : selector.select(timeoutMillis);
}private void processSelectedKeys() {if (selectedKeys != null) {processSelectedKeysOptimized();} else {processSelectedKeysPlain(selector.selectedKeys());}
}

其实,netty 也不难对吧
学习netty,主要学习它的设计思想和对性能优化的巧妙处理,当工作需要时,能够灵活运用

二、NioEventLoopGroup 对象的创建过程

2.1 创建流程图

在这里插入图片描述
可以看到,其实我们传的线程数量实际控制的是NioEventLoop对象创建的数量,而每个 NioEventLoop 其实是一个Executor执行器,那么至此,我们只是相当于创建了两个 NioEventLoopGroup 对象,他们分别有自己的children执行器 NioEventLoop 数组,同一个数组内的 NioEventLoop 共享一个ThreadPerTaskExecutor执行器,但是现在这个执行器后续如何处理事件和如何调度还不知道,后续会讲到,本文先看看创建NioEventLoopGroup对象都做了什么
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

水位传感器优点有哪些

水位传感器是一种用于检测液体水位的重要设备&#xff0c;在各种工业和民用场景中起着至关重要的作用。其中&#xff0c;光学液位传感器作为一种先进的水位检测技术&#xff0c;在市场上备受青睐&#xff0c;其优点主要包括以下几个方面。 光学液位传感器内部所有元器件均经过…

基于springboot+vue的游艇停泊系统

一、系统架构 前端&#xff1a;vue2 | element-ui |html 后端&#xff1a;springboot | mybatis-plus 环境&#xff1a;jdk1.8 | mysql | maven | node 二、代码及数据库 三、功能介绍 01. web端-登录 02. web端-系统首页1 03. web端-系统首页2 04. web端-泊位 05. web…

Open-Sora:开源版的Sora

项目简介 本项目希望通过开源社区的力量复现Sora&#xff0c;由北大-兔展AIGC联合实验室共同发起&#xff0c;当前我们资源有限仅搭建了基础架构&#xff0c;无法进行完整训练&#xff0c;希望通过开源社区逐步增加模块并筹集资源进行训练&#xff0c;当前版本离目标差距巨大&…

制作github.io学术个人主页

制作如图的学术个人主页。About me - Xianwen Ling’s Blog 学术个人主页是一个学者展示个人学术成果和研究方向的重要工具。个人主页可以集中展示学者的研究论文、出版物、演讲和发布的项目等学术成果&#xff0c;这样其他人可以更方便地了解和评估学者的研究贡献。个人主页可…

国产FTP文件传输服务器需要具备哪些关键特性?

国产FTP文件传输服务器是指根据中国国内信息技术创新&#xff08;信创&#xff09;的要求和标准&#xff0c;自主研发的文件传输服务器软件。这类软件旨在替代传统的FTP服务器&#xff0c;以更好地适应国产化和信息安全的需要。国产FTP文件传输服务器通常需要具备以下要求&…

苹果收购的法国AI初创公司Datakalab是什么来头?!iOS 18将加入AI功能!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

Spring SpringBoot(详解)

1. Spring简介 1.1 Spring 核心设计思想 1.1.1 Spring 是什么&#xff1f; Spring 是包含了众多⼯具⽅法的 IoC 容器。Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;Spring ⽀持⼴泛的应⽤场景&#xff0c;它…

配置网络设备的密码设置以及忘记密码的恢复方式以及实现全网互通

1.实验拓扑图&#xff1a; 2.实验需求&#xff1a; 1.推荐步骤 1.1配置IP&#xff1a; 不过多说了&#xff0c;较为基础&#xff08;略&#xff09; 2.推荐步骤 2.所有网络设备配置console接口密码 首先进入全局模式&#xff0c;输入以下代码(进入接口console接口0给其配置密…

源代码图纸文档防泄密场景方案分析

场景描述&#xff1a; 近年来&#xff0c;各类数据泄露事件频发&#xff0c;且呈不断增长趋势&#xff0c;给各类组织机构造成了巨大的经济损失。调查显示&#xff0c;在互联网接入单位因内部重要机密通过网络泄密而造成重大损失的事件中&#xff0c;97%都是因内部员工有意或无…

ArgoCD集成部署到Kubernetes

1&#xff1a;环境 kubernetes1.23.3ArgoCD2.3.3 2&#xff1a;ArgoCD介绍 Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Argo CD是一个基于Kubernetes的声明式的GitOps工具。 那么&#xff0c;什么是GitOps呢&#xff1f; GitOps是以Git为基…

通配符(泛域名)SSL证书在使用上有什么优势?

通配符证书在使用上具有以下显著优势&#xff1a; 1. 安全性&#xff1a; - 统一加密保护&#xff1a;通配符证书基于SSL/TLS协议&#xff0c;为一个主域名及其所有子域名提供相同的高强度数据加密服务。无论用户访问的是mail.example.com、shop.example.com还是其他任何以exam…

Python | Leetcode Python题解之第48题旋转图像

题目&#xff1a; 题解&#xff1a; class Solution:def rotate(self, matrix: List[List[int]]) -> None:n len(matrix)# 水平翻转for i in range(n // 2):for j in range(n):matrix[i][j], matrix[n - i - 1][j] matrix[n - i - 1][j], matrix[i][j]# 主对角线翻转for …

ArcGIS无法开始编辑TIN!开始编辑TIN显示灰色

ArcGIS无法开始编辑TIN&#xff01;开始编辑TIN显示灰色&#xff1f; 解决方案&#xff01; 1、确认自定义——扩展模块中空间分析、3D分析模块勾选。 2、确认以上后&#xff0c;还是不能编辑的话&#xff0c;我们可以调出 3D分析分析工具条&#xff0c;你就会发现。TIN编辑工…

C#带引导窗体的窗体设计方法:创建特殊窗体

目录 1.设计操作流程 2.实例 &#xff08;1&#xff09;Resources.Designer.cs &#xff08;2&#xff09;Frm_Main.Designer.cs &#xff08;3&#xff09;Frm_Main.cs &#xff08;4&#xff09;Frm_Start.Designer.cs &#xff08;5&#xff09;Frm_Start.cs &#…

上海·得物技术沙龙-「无线技术」专场报名开启!

本次无线沙龙聚焦于最新的技术趋势和实践&#xff0c;将在上海/线上为你带来四个令人期待的演讲话题&#xff0c;包括&#xff1a;《快手主App启动接口带宽优化实践》、《得物App视频体验优化实践》、《Chromium内核架构和网络库优化介绍》、《得物App发热监控实践》。相信这些…

【Java Spring MVC项目异常解决】HTTP 500

HTTP 500状态码表示“内部服务器错误”&#xff08;Internal Server Error&#xff09;。这是一个通用的错误响应&#xff0c;表明服务器在处理请求时遇到了预料之外的情况&#xff0c;导致无法完成请求。500错误是服务器端错误的一种&#xff0c;与客户端无关。在Web开发中&am…

小波变换和多分辨率处理

第七章的内容&#xff0c;发现冈萨雷斯的第二版要比第三版写的清楚很多。我在对比第三版和第二版的内容之后&#xff0c;感觉更容易理解。j级图像滤波之后一抽样因子为2进行抽样&#xff0c;产生空间分辨率变成1/4的图像叫j-1级近似。然后插值因子为2插值分辨率又变成了原来大小…

字节跳动(社招)三面算法原题

TikTok 喘息 继上月通过强制剥离 TikTok 法案后&#xff0c;美国众议院在当地时间 20 日下午以 360 票赞成 58 票反对通过了新的法案&#xff1a;剥离 TikTok 的期限由生效后 165 天调整至 270 天之内&#xff0c;即今年 11 月的美国总统大选后。 之前我们讲过&#xff0c;TikT…

中国新能源汽车快速发展 充电模块市场前景广阔

中国新能源汽车快速发展 充电模块市场前景广阔 充电模块是一种用于充电的电子模块&#xff0c;指可以直接焊装在印刷电路板上的、以模块方式体现的电源供应器&#xff0c;主要由电源管理电路、充电控制电路和充电保护电路等部分组成。充电模块在充电系统中不仅负责提供能源电力…

学python的第二十天

多线程 以下内容来源于《看漫画学Python》这本书&#xff0c;前面十几天好多内容参考过本书内容&#xff0c;写的挺好。 1 线程相关知识 1.1 进程 一个进程就是一个正在执行的程序&#xff0c;每一个进程都有自己独立的一块内存空间&#xff0c;一组系统资源。在进程概念中&…