Netty第一部

news2025/4/8 18:11:43

一、select和epoll原理分析

外设设备网卡、鼠标、键盘等通过总线写到内存中,中间就有DMA拷贝,操作系统怎么知道内存中有数据了,这就需要操作系统通过中断机制确定,如果有中断信号过来,cpu会首先打断用户程序执行,响应硬件的程序的信号,然后再恢复用户程序的执行;不同外设设备对应的驱动程序不同,发送的中断信号也就不同,操作系统根据对应信号做出相应的处理

1、操作系统如何处理中断请求

内核和设备驱动是通过中断方式来处理的。所谓中断,可以理解当设备上有数据到达时,会给cpu的相关引脚上发一个电压变化,以通知cpu来处理数据;硬件产生的信号需要cpu立马处理,否则数据可能丢失

网络模块比较耗时,中断时会过度占用cpu,导致cpu无法响应其它设备,因此在Linux中段处理函数分上半部和下半部,上半部通知cpu,下半部响应

2、进程阻塞

操作系统为了支持多任务,实现进程调度功能,会把进程分为“运行”和“等待”等几种状态。运行状态是获取cpu使用权,正在执行的代码是运行状态;等待状态是阻塞状态,详情参照下图(个人理解)

3、内核接收网络数据

一旦有cpu响应中断操作就会拷贝数据到内存,经过协议层的解析到socket应用层就有了数据,就会唤醒进程A,重新进入到工作队列中

4、同时监视多个socket的简单方法

select实现思路很直接。假如程序同时监视socket1、socket2、socket3,那么调用select之后,操作系统把进程A分别加入到这三个socket的等待列表中,当任何一个socket收到数据,都会中断程序唤醒进程A,所有的socket的等待队列中的进程A都会被移除,加入到工作队列中

如上图所示,进程A只知道Socket有数据过来,并不知道哪些Socket有数据,所以就需要遍历Socket列表;并且处于遍历的性能考虑,select最大只能监视1024个Socket

5、epoll的原理

当执行epoll_create方法时,内核会创建一个eventpoll对象;当Socket收到数据后,中断程序会操作eventpoll对象,而不直接操作进程;中断程序会给rdlist引用收到的数据Socket2、Socket3,当执行epoll_wait,如果rdlist已经引用了Socket,那么epoll_wait直接返回,如果rdlist为空,阻塞进程

当Socket接收到数据,中断程序一方面修改rdlist,另一个方面唤醒 eventpoll等待队列的线程,线程A回到工作队列中去,由于rdlist引用了接收了数据的Socket,所以不用对所有的进行遍历

二、Netty基础

1、Netty的组件

  1. Bootstrap是Netty框架的启动类和主入口类,分为客户端类Bootstrap和服务器类ServerBootstrap两种。
  2. EventLoop暂时可以看成一个线程、EventLoopGroup 自然就可以看成线程组。
  3. Channel是Java NIO的一个基本构造。
  4. ChannelHandler和ChannelPipeline:每个事件都可以被分发给 ChannelHandler 类中的某个用户实现的方法,既然事件分为 入站和出站,用来处理事件的 ChannelHandler 也被分为可以处理入站事件的 Handler 和出站 事件的 Handler,当然有些 Handler 既可以处理入站也可以处理出站;这些 ChannelHandler 都放在 ChannelPipeline 中统一管理
  5. ChannelFuture:异步获取结果的类,类似于JDK的java.util.concurrent.Future类

2、使用示例

<dependency>
 <groupId>io.netty</groupId>
 <artifactId>netty-all</artifactId
 <version>4.1.42.Final </version>
 <scope>compile</scope>
</dependency>

服务端

public class EchoServer  {
    private static final Logger LOG = LoggerFactory.getLogger(EchoServer.class);

    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws InterruptedException {
        int port = 9999;
        EchoServer echoServer = new EchoServer(port);
        LOG.info("服务器即将启动");
        echoServer.start();
        LOG.info("服务器关闭");
    }

    public void start() throws InterruptedException {
        /*线程组*/
        EventLoopGroup group  = new NioEventLoopGroup();
        try {
            /*服务端启动必备*/
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    });

            /*异步绑定到服务器,sync()会阻塞到完成*/
            ChannelFuture f = b.bind().sync();
            LOG.info("服务器启动完成。");
            /*阻塞当前线程,直到服务器的ServerChannel被关闭*/
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync();
        }
    }


}

客户端

public class EchoClient {

    private final int port;
    private final String host;

    public EchoClient(int port, String host) {
        this.port = port;
        this.host = host;
    }

    public void start() throws InterruptedException {

        /*线程组*/
        EventLoopGroup group  = new NioEventLoopGroup();
        try {
            /*客户端启动必备,和服务器的不同点*/
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)/*指定使用NIO的通信模式*/
                    /*指定服务器的IP地址和端口,和服务器的不同点*/
                    .remoteAddress(new InetSocketAddress(host,port))
                    /*和服务器的不同点*/
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new EchoClientHandler());

                        }
                    });
            /*异步连接到服务器,sync()会阻塞到完成,和服务器的不同点*/
            ChannelFuture f = b.connect().sync();
            f.channel().closeFuture().sync();/*阻塞当前线程,直到客户端的Channel被关闭*/
        } finally {
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new EchoClient(9999,"127.0.0.1").start();
    }
}

服务端的ChannelHandler

public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf)msg;
        System.out.println("server accept :" + in.toString(CharsetUtil.UTF_8));
        ctx.writeAndFlush(in);

        //ctx.close();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("连接已建立");
        super.channelActive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

客户端的ChannelHandler

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    /*读取到网络数据后进行业务处理,并关闭连接*/
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("client Accept"+msg.toString(CharsetUtil.UTF_8));
        //关闭连接
        ///ctx.close();
    }

    /*channel活跃后,做业务处理*/
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer(
                "Hello,Netty",CharsetUtil.UTF_8));
//        ctx.pipeline().write()
//        ctx.channel().write()
        ctx.alloc().buffer();
    }
}

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

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

相关文章

java进行支付宝支付(沙箱环境)

目录 1.准备工作 2.idea配置文件准备 3.后端代码编写 接口1&#xff1a;支付订单 接口2&#xff1a;查询订单 接口3&#xff1a;订单退款 接口4&#xff1a;查询退款结果 接口5&#xff1a;获取总账单 接口6&#xff1a;取消订单 接口7&#xff1a;回调接口 定时任务…

【stata基础代码大全 】 可独立完成一篇实证

【stata基础代码大全 】 可独立完成一篇实证 用stata打开&#xff0c;直接替换自己需要的变量就行&#xff0c;小白友好❗️❗️❗️ 文件包括以下内容 一、数据预处理 二、Stata中数据的基本处理 *(1)取年份 *(2)剔除数据中的样本 *(3)生成新的变量 *(4)给变量添加标签 *(5)生…

开关电源测试过压保护的测试标准及其方法

过压保护的原理 过压保护是电压超过预定值时降低电压的一种方式&#xff0c;原理是通过电路中的电压检测电路来检测电路中的电压是否超过了设定的阈值&#xff0c;如果超过了阈值&#xff0c;就会触发过压保护器件&#xff0c;使电源断开或使受控设备电压降低&#xff0c;保护电…

智慧矿山:AI算法在带式运输机中的异物识别应用

随着现代农业和工业的发展&#xff0c;带式运输机在各种生产作业中发挥着越来越重要的作用。然而&#xff0c;在带式运输机运行过程中&#xff0c;可能会混入各种异物&#xff0c;这些异物的存在可能会对运输过程和设备本身造成损害。为了解决这一问题&#xff0c;本文将介绍一…

VVG PAD DM蓝牙5.2双模热插拔PCB

键盘使用说明索引&#xff08;均为出厂默认值&#xff09; 软件支持&#xff08;驱动的详细使用帮助&#xff09;一些常见问题解答&#xff08;FAQ&#xff09;请认真阅读本说明首次使用步骤蓝牙配对规则&#xff08;重要&#xff09;蓝牙和USB切换键盘默认层默认触发层0的FN键…

低代码,程序员提高生产力的开发工具

目录 一、什么是低代码&#xff1f; 二、低代码的本质是什么&#xff1f; 三、低代码平台的搭建能力 四、写在最后 一、什么是低代码&#xff1f; 简单来说&#xff0c;低代码是一种用于应用程序开发的模块化方法&#xff0c;它能有效减少应用程序的开发时间。基于可重用的、组…

Nginx负载均衡 以及Linux前后端项目部署

一、Nginx简介 Nginx是一款高性能的开源Web服务器和反向代理服务器。它由俄罗斯的程序设计师Igor Sysoev创建&#xff0c;旨在解决传统Web服务器的性能限制问题。 Nginx采用事件驱动的架构和异步非阻塞的处理方式&#xff0c;使其能够处理大量并发连接&#xff0c;并具备良好…

机房精密空调发生内部设备通信故障不一会压缩机就停止工作,怎么处理?

环境: 山特AT-DA810U 精密空调 问题描述: 机房精密空调发生内部设备通信故障不一会压缩机就停止工作,怎么处理? 回风处不显示温湿度 解决方案: 1.进入诊断模式工程师密码333333 看到压缩机关闭了,强制输出测试一下压缩机正常 2.尝试更换温湿度传感器模块网口,重启…

1985-2022年全国各地级市绿色专利申请和授权数据

1985-2022年全国各地级市绿色专利申请和授权数据 1、时间&#xff1a;1985-2022年 2、指标&#xff1a;年份、地区、行政区划代码、所属省份、所属地域、绿色专利申请总量、绿色专利申请_发明专利、绿色专利申请_实用新型专利、绿色专利授权总量、绿色专利授权_发明专利、绿色…

IT老鸟给开发者升职加薪的小技巧

前言&#xff1a; 升职加薪对大多数人来说都是工作重要动力所在&#xff0c;但总存在“青出于蓝而胜于蓝”&#xff0c;后来人居上的情况。很多人不清楚&#xff0c;自己兢兢业业&#xff0c;任劳任怨&#xff0c;到头来还是得不到领导的重视&#xff0c;身边一起过来的同事都成…

学习笔记|两因素析因设计的方差分析|效应量|统计分析策略|《小白爱上SPSS》课程:SPSS第九讲 | 两因素析因设计的方差分析,超级详细

目录 学习目的软件版本原始文档两因素析因设计的方差分析一、实战案例二、统计策略三、SPSS操作1、正态性检验2、方差分析 四、结果解读Tips&#xff1a;效应量越大越好吗&#xff1f;统计分析策略 五、简单效应操作及结果1、SPSS操作2、结果解读 六、规范报告1、规范表格2、规…

[idea]关于idea开发乱码的配置

在JAVA开发中&#xff0c;一般统一设置为UTF-8的编码&#xff0c;包括但不限于开发工具、日志架构、虚拟机、文件编码等。常见配置如下&#xff1a; 1、IDEA工具 在idea64.exe.vmoptions、idea.exe.vmoptions中添加&#xff1a; -Dfile.encodingUTF-8 2、JAVA 运行在window…

web - 会话技术

文章目录 目录 文章目录 前言 一 . 会话 1.1 会话管理概述 1.2 会话管理实现手段 二 . Cookie 2.1 cookie概述 2.2 cookie的使用 2.3 Cookie的时效性 2.4 Cookie的提交路径 三 . Session 3.1 HttpSession概述 3.2 HttpSession的使用 3.3 HttpSession时效性 四 .…

9.MySQL索引的操作

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 索引操作 查询索引 创建主键索引 唯一索引的创建 普通索引的创建 全文索引的创建 删除索引 索引创建原则 索引操作 查询索引 第一种方法&#xff1a; show keys from 表名\G 我们了解其中几个就好。 第二种方法…

主从复制(gtid方式)

基于事务的Replication&#xff0c;就是利用GTID来实现的复制 GTID&#xff08;全局事务标示符&#xff09;最初由google实现&#xff0c;在MySQL 5.6中引入.GTID在事务提交时生成&#xff0c;由UUID和事务ID组成.uuid会在第一次启动MySQL时生成&#xff0c;保存在数据目录下的…

自动化测试的一些问题合集

问题1、 ipykernel_launcher.py: error: unrecognized arguments: usage: ipykernel_launcher.py [-h] [--id ID] [--test TEST] [--env ENV] ipykernel_launcher.py: error: unrecognized arguments: --ip127.0.0.1 --stdin9003 --control9001 --hb9000 --Session.signature_…

取消google账户银行卡支付信息Remove google payment method

在Google payment method里面&#xff08;网址https://payments.google.com/&#xff09;选择payment methods&#xff0c;然后移除即可。

SortableJS:vuedraggable实现元素拖放排序

文档&#xff1a;https://sortablejs.github.io/Sortable/github&#xff1a;https://github.com/SortableJS/SortableVue2: https://github.com/SortableJS/Vue.DraggableVue3: https://github.com/SortableJS/vue.draggable.nextnpm https://www.npmjs.com/package/vuedragga…

《低代码指南》——维格云机器人常见报错怎么解决?

在使用维格机器人调用维格表的API过程中,可能会出现机器人执行结果未达到预期的情况,此时可能是机器人运行出现了问题;通过点击这个机器人右上角的“运行历史”可以查看运行记录,通过对运行记录的分析,可以推断出问题所在,然后进行修改。 而对于运行历史的分析,主要是针…

Android NDK开发详解之调试和性能分析的ndk-gdb

Android NDK开发详解之调试和性能分析的ndk-gdb 要求用法选项 NDK 包含一个名为 ndk-gdb 的 Shell 脚本&#xff0c;可以启动命令行原生调试会话。偏好使用 GUI 的用户则应阅读在 Android Studio 中调试这篇文档。 要求 要运行命令行原生调试&#xff0c;必须满足以下要求&am…