Netty源码解读-server端(一)

news2024/11/25 16:34:24

一、回顾NIO中的server

下面是我在学习nio时,写的selctor版本的服务端,具体代码如下:

public static void nioSelectorServer() throws Exception{

        //1。创建Selector
        Selector selector = Selector.open();

        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);//默认是true,设置为false就是非阻塞模式(下面的accept方法就会变成非阻塞)

        //2。建立selector 和 channel 的联系(注册)
        //SelectionKey 就是将来事件发生后,通过它可以知道事件和哪个channel的事件
        SelectionKey ssckey = ssc.register(selector, 0, null);
        // key 只关注 accept 事件
        ssckey.interestOps(SelectionKey.OP_ACCEPT);
        log.info("register key:{}",ssckey);

        ssc.bind(new InetSocketAddress(8080));

        while (true) {
            //3.select当啊,没有事件发生,线程阻塞。有事件发生,线程才会恢复运行
            //在事件未处理时,select不会阻塞。( 处理有两种方法:key.cancel() 和 key.chaneel().accept()  )
            selector.select();
            //4.处理事件,selectedKeys 内部包含了所有发生的事件
            Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
            while (iter.hasNext()) {
                SelectionKey key = iter.next();
                //!!!处理key时,要从selectedKey集合中删除,否则下厨处理可能抛出空指针(至于为什么可以看image/1.png)
                iter.remove();
                log.info("key: {}",key);
                //5.区分事件类型
                if (key.isAcceptable()) {
                    //如果下面三行取消,whilet(true)代码块就会一直运行,打印上面的log
                    ServerSocketChannel channel = (ServerSocketChannel)key.channel();
                    SocketChannel sc = channel.accept();//处理事件
                    sc.configureBlocking(false);
                    SelectionKey scKey = sc.register(selector, 0, null);
                    scKey.interestOps(SelectionKey.OP_READ);
                    log.info("{}",sc);
                }else if (key.isReadable()) {
                    try {
                        SocketChannel channel = (SocketChannel) key.channel();//拿到触发事件的channel
                        ByteBuffer buffer = ByteBuffer.allocate(16);
                        int read = channel.read(buffer);//如果是正常断开,read方法返回值是-1
                        if (read == -1){
                            key.cancel();//!!!!
                        }else {
                            buffer.flip();
                            System.out.println(Charset.defaultCharset().decode(buffer));
                        }
                    }catch (IOException e) {
                        e.printStackTrace();
                        //!!!因为客户端断开了,因此需要将key取消(从selector 的 keys 集合中真正删除key)
                        key.cancel();
                    }
                }
            }
        }

    }

从上述代码中,我们可以看到几个重要的步骤:
在这里插入图片描述

二、Bind源码分析

1.大体观摩

下面是我编写的netty版本server端的demo
在这里插入图片描述
咱可以重点看一下doBind方法中调用的下面这两个方法,注意线程是怎么从main线程变成Nio线程的
在这里插入图片描述

2.initAndRegister方法

2.1 initAndRegister方法可以大体上看成下面两个部分,上面是init,下面是register
在这里插入图片描述

2.2 init相关步骤

2.2.1往下追channelFactory.newChannel()的底层,发现是init其实就是通过反射的方式调用构造方法:
在这里插入图片描述
2.2.2上面这个初始化的方法其实会调用到NioServerSocketChannel的构造方法中去,下面是其构造方法的部分源码:
从中可以得知nio原生的ServerSocketChannel.open操作是在此执行的。
在这里插入图片描述

在这里插入图片描述

2.2.3回到initAndRegister方法,咱们在看看其调用的init()做了什么事情?
答:主要就是给NioServerSocketChanel添加了一个handler处理器
在这里插入图片描述

小结:init相关操作主要做了两件事:
1.创建出了NioServerSocketChannel对象,ServerSocketChannel.open()
2.为NioServerSocketChannel对象添加了一个handler处理器,等待后续调用执行






2.3 register相关步骤

2.3.1回到initAndRegister方法,咱继续看 config().group().register(channel); 方法的底层,需要追很深哦
可以发现在这里面发生了线程的切换,注意切换为Nio线程执行时,main线程会继续往下执行,这里先提一嘴留个影响。

在这里插入图片描述
2.3.2继续追register0,首先看其内部调用的doRegister
从中可以得知nio原生的ServerSocketChannel的register方法在此执行
在这里插入图片描述
2.3.3继续看register0中调用的 pipeline.invokeHandlerAddedIfNeeded() 的源码
这个方法其实就是执行了2.2.3步骤中添加的handler,为ServerSocketChannel添加acceptHandler,当accept事件发生后建立链接
在这里插入图片描述

2.3.4继续看register0中调用的 safeSetSuccess(promise)
这个方法的作用是给promise对象赋值,好让doBind方法中的main线程继续执行后续逻辑
在这里插入图片描述
小结:register相关操作主要做了3件事:
1.将serverSocketChannel绑定到了Selector上
2.执行了前面init方法中准备好的handler,目的是给NioServerSocketChannel添加一个关注accept事件的handler
3.当前面两部都完成后,让dobind方法中的main线程继续执行doBind0

3.doBind0方法

上面2.3.4可以得知执行到这一步时NioServerSocket以及绑定了一个Accept事件
dobind0其底层调用到了AbstractChannel中的bind方法
在这里插入图片描述

3.1dobind方法底层

底层相当于就是执行nio原生的ServerSocketChannel的bind方法
在这里插入图片描述

3.2invokeLater方法底层

它会去执行每个handler的active方法,重点是看head头节点的active
在这里插入图片描述
从其底层可以看出是调用到了nio的原生方法selectionKey.interestOps,让selector关注到accept事件
在这里插入图片描述
小结:dobind0主要做了2件事:
1.执行ServerSocketChannel的bind方法,绑定端口号
2.执行selectionKey.interestOps,关注Accept事件

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

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

相关文章

c++ bind 函数讲解

1.bind 函数的使用详解 可以将bind函数看作一个通用的函数适配器&#xff0c;它接受一个可调用对象&#xff0c;生成一个新的可调用对象来“适应”原对象的参数列表。 调用bind的一般形式&#xff1a;auto newCallable bind(callable,arg_list); 其中&#xff0c;newCallab…

从零实现深度学习框架——再探多层双向RNN的实现

来源&#xff1a;投稿 作者&#xff1a;175 编辑&#xff1a;学姐 往期内容&#xff1a; 从零实现深度学习框架1&#xff1a;RNN从理论到实战&#xff08;理论篇&#xff09; 从零实现深度学习框架2&#xff1a;RNN从理论到实战&#xff08;实战篇&#xff09; 从零实现深度…

【Vue3】首页主体-面板组件封装

首页主体-面板组件封装 新鲜好物、人气推荐俩个模块的布局结构上非常类似&#xff0c;我们可以抽离出一个通用的面板组件来进行复用 目标&#xff1a;封装一个通用的面板组件 思路分析 图中标出的四个部分都是可能会发生变化的&#xff0c;需要我们定义为可配置主标题和副标题…

您可以使用 21 个很棒的搜索引擎来代替 Google

在过去的 20 年里&#xff0c;Google 一直是大多数人用于日常搜索、产品研究和了解最新消息的搜索引擎。凭借其长期的统治地位和大部分市场份额&#xff0c;很难说任何搜索引擎都能提供比谷歌更好的结果。由于这种市场主导地位&#xff0c;谷歌也一直是SEO和营销专业人士关注的…

随笔-老子不想牺牲了

18年来到这个项目组&#xff0c;当时只有8个人&#xff0c;包括经常不在的架构师和经理。当时的工位在西区1栋A座&#xff0c;办公桌很宽敞。随着项目的发展&#xff0c;入职的人越来越多&#xff0c;项目的工位也是几经搬迁。基本上每次搬迁时&#xff0c;我的工位都是挑剩下的…

Allegro如何实现同一个屏幕界面分屏显示操作指导

Allegro如何实现同一个屏幕界面分屏显示操作指导 在做PCB设计的时候,会需要分屏显示,比如一边是放大的视图,另外一边是缩小的视图,Allegro支持同一个屏幕界面下进行分屏显示,如下图 而且会实时同步起来 如何分屏,具体操作如下 点击View

(python)降低图像质量

降低数字图像质量(python实现) 目录 降低数字图像质量(python实现)一、分别采用五种不同的方式来降低图像的质量1. 给图像添加椒盐噪声2. 给图像添加高斯噪声3. 对图像进行高斯模糊4. 对图像进行运动模糊5. 对图像进行插值下采样二、实现代码一、分别采用五种不同的方式来降…

操作系统(六)磁盘调度算法与优化

操作系统&#xff08;六&#xff09;磁盘调度算法与优化 一、磁盘调度算法 时间指标 寻找时间&#xff1a;在读/写数据前&#xff0c;将磁头移动到指定磁道需要的时间延迟时间&#xff1a;通过旋转盘面&#xff0c;将磁头定位到目标扇区所需的时间传输时间&#xff1a;从磁盘…

Leetcode.1124 表现良好的最长时间段

题目链接 Leetcode.1124 表现良好的最长时间段 Rating &#xff1a; 1908 题目描述 我们认为当员工一天中的工作小时数大于 8 小时的时候&#xff0c;那么这一天就是「劳累的一天」。 所谓「表现良好的时间段」&#xff0c;意味在这段时间内&#xff0c;「劳累的天数」是严格…

argocd 调研

Argo CD 是基于 Kubernetes 的声明式&#xff0c; GitOps 持续交付工具。GitOps AgentGitOps IaC Git CI/CD&#xff0c;即基于 IaC 的版本化 CI/CD。它的核心是使用 Git 仓库来管理基础设施和应用的配置&#xff0c;并且以 Git 仓库作为基础设施和应用的单一事实来源。Git …

Windows 11 办公实用效率小技巧总结(持续更新)

Win11 办公实用效率小技巧总结:1. 虚拟桌面2. 拖拽任务窗口转移到不同虚拟桌面3. 自定义多网页名称4. Focus专注组件5. 多选项分屏6. 抖一抖最小化1. 虚拟桌面 虽然过去只有 Linux&#xff0c; Mac 系统中有虚拟桌面&#xff0c;而且在win10 中也实现了这个功能&#xff0c;但…

Springboot835学生成绩分析系统--java

开发语言&#xff1a;Java 框架&#xff1a;Springboot 技术&#xff1a;JSP JDK版本&#xff1a;JDK1.8 目 录 1 绪 论 5 1.1课题背景 5 1.2 课题研究的意义 5 1.3 系统实现的功能 5 1.4 课题研究现状 5 2系统相关技术 7 2.1 Java技术 7 2.2 B/S架构 7 2.3 MySQL 介绍 7 2.4My…

zabbix邮件报警配置

在Zabbix服务端设置邮件报警&#xff0c;当被监控主机宕机或者达到触发器预设值时&#xff0c;会自动发送报警邮件到指定邮箱。 邮件服务可以使用系统自带的邮件服务来发送邮件或者使用其他邮件服务调用第三方邮件来发送警告邮件。 一、开启发件服务器SMTP功能 这里发送邮件的…

初始C++(四):内联函数

文章目录一.内联函数概念二.内联函数用法三.内联函数的特性四.内联函数和宏一.内联函数概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 二.内联函…

SpringBoot环境-MySQL主从复制,读写分离的实现

目录 概述 环境 主从复制 读写分离 概述 记录在MySQL数据库中主从复制以及SpringBoot环境操作MySQL数据库读写分离的实现步骤。 背景 &#xff1a;因为我们在对数据库进行操作时&#xff0c;如果读写操作都由一台数据库承担的话压力会比较大&#xff0c;为了减轻数据库压力&…

【Linux】rsyslog日志服务(配置,测试、日志转储)

一、rsyslog简介 Rsyslog的全称是 rocket-fast system for log ,可用于接受来自各种来源的输入&#xff0c;转换 它们&#xff0c;并将结果输出到不同的目的地。 它提供了高性能、强大的安全功能和模块化设计。虽然rsyslog最初是一个常规的系 统日志&#xff0c;但它已经发展成…

H5APP开发封装流程

1.利用H5写想要的功能 2.打包APP 3.手机安装 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum-scale1.0, user-sca…

【基础】Flink -- Time and Window

Flink -- Time and WindowFlink 时间语义水位线 Watermark水位线的概念有序流中的水位线乱序流中的水位线水位线的特性水位线的基本使用水位线生成策略内置水位线生成器自定义水位线策略在自定义数据源中发送水位线窗口 Window窗口的基本概述窗口的基本概念窗口的分类窗口的 AP…

ccc-Backpropagation-李宏毅(7)

文章目录NotationBackpropagationForward passBackward passSummaryNotation 神经网络求解最优化Loss function时参数非常多&#xff0c;反向传播使用链式求导的方式提升计算梯度向量时的效率&#xff0c;链式法则如下&#xff1a; Backpropagation 损失函数计算为所有样本…

Pulsar

一、简介Apache Pulsar是Apache软件基金会顶级项目&#xff0c;是下一代云原生分布式消息流平台&#xff0c;集消息、存储、轻量化函数式计算为一体&#xff0c;采用计算与存储分离架构设计&#xff0c;支持多租户、持久化存储、多机房跨区域数据复制&#xff0c;具有强一致性、…