当前位置: 首页 > news >正文

netty入门-3 EventLoop和EventLoopGroup,简单的服务器实现

文章目录

  • EventLoop和EventLoopGroup
    • 服务器与客户端基本使用
    • 增加非NIO工人
    • NioEventLoop 处理普通任务与定时任务
  • 结语

EventLoop和EventLoopGroup

二者大概是什么这里不再赘述,前一篇已简述过。
不理解也没关系。
下面会简单使用,看了就能明白是什么
这篇文章只说NioEventLoopGroup
后续文章会有服务器创建类BootStrap的方法总结。

服务器与客户端基本使用

EventLoopGroup的常用实现类是NioEventLoopGroup
就以此为例,我们来看这两者,在使用netty创建一个服务器的过程中处于什么位置。

PS:我觉得既然是专注于这个东西怎么用,就不要太纠结于底层。
我当时看到childHandler,就想弄明白这个到底是怎么把Handler加到新ChannelPipeline中的。这就要涉及源码。下面这个链式调用其他部分也是一样。想搞明白每个调用的底层还是需要看源码。会给初学者带来没必要的精力耗费。我觉得需要收住好奇心,先会简单使用,再说底层实现。

//服务端
//ServerBootstrap相当于提供了创建服务器的辅助类。允许通过链式调用更优雅的启动一个服务器。
//我们通过一系列链式调用完成了服务器的创建。
new ServerBootstrap()//group相当于我们配置EventLoopGroup的地方,它将用于后续的事件处理.group(new NioEventLoopGroup(1), new NioEventLoopGroup(2))//channel指定通道类型,NioServerSocketChannel是netty的封装类,即NIO中的升级版.channel(NioServerSocketChannel.class)//这个名字child代表子通道,什么意思?即我们有一个NioServerSocketChannel来处理Accept请求。接受的每个连接都会创建自己的SocketChannel用于通信,可当作child,即子通道。//所以顾名思义子通道处理器。即为新创建的每一个子通道都会绑定这个ChannelInitializer,那么它又是做什么的?//ChannelInitializer会在每个新Channel被注册到EventLoopGroup时执行内部我们重写的initChannel方法,将我们在initChannel方法中自定义的处理器添加到我们这个channel的channelpipeline中。即为我们新连接的Channel添加一个handler。关于handler和pipeline,在上篇中简单讲述了是什么。//简单来说,它是对每个新建立的连接Channel,指定我们写好的处理逻辑,之后Channel的读写操作都会经过这些逻辑。.childHandler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) {//这里的参数我猜测就是我们新连接的channel//这里对新channel添加我们自定义的handlerch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ByteBuf byteBuf = msg instanceof ByteBuf ? ((ByteBuf) msg) : null;if (byteBuf != null) {byte[] buf = new byte[16];ByteBuf len = byteBuf.readBytes(buf, 0, byteBuf.readableBytes());log.debug(new String(buf));}}});}//绑定端口,并sync阻塞住}).bind(8080).sync();

这里还有一些理解
channel()方法,将我们指定的NioServerSocketChannel 注册到group中的第一个group内的某个EventLoop,由该EventLoop监听。第一个group中的EventLoop被称为Boss,专门处理连接请求。
所有连接由NioServerSocketChannel处理,同时新连接产生的SocketChannel注册到第二个group内的某个EventLoop,由该EventLoop监听。这些EventLoop被称为Worker。处理读写请求。
上面程序中相当于有两个Worker,因为创建EventLoopGroup时参数为2。

所以小结一下。每个Channel都会由一个EventLoop监听。并且在事件发生时调用对应的处理器进行处理。即完成对事件的监听和处理。

//客户端
//通过链式调用,拿到连接完毕的Channel
Channel channel = new Bootstrap().group(new NioEventLoopGroup(1)).handler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {System.out.println("init...");ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));}}).channel(NioSocketChannel.class).connect("localhost", 8080).sync().channel();// 发送消息
channel.writeAndFlush(ByteBufAllocator.DEFAULT.buffer().writeBytes("wangwu".getBytes()));Thread.sleep(2000);channel.writeAndFlush(ByteBufAllocator.DEFAULT.buffer().writeBytes("wangwu".getBytes()));

这里多创建几个客户端发消息,会发现服务器中的两个Worker会分别处理属于自己管理Channel的事件。

增加非NIO工人

下面程序有两个handler
LoggingHandler"myhandler"
引入了一个我们自己创建的DefaultEventLoopGroup 去处理"myhandler"的任务,即非NIO工人

//额外的工程组
//非NIO工人2个
DefaultEventLoopGroup normalWorkers = new DefaultEventLoopGroup(2);
new ServerBootstrap().group(new NioEventLoopGroup(1), new NioEventLoopGroup(2)).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch)  {ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));ch.pipeline().addLast(normalWorkers,"myhandler",new ChannelInboundHandlerAdapter() {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ByteBuf byteBuf = msg instanceof ByteBuf ? ((ByteBuf) msg) : null;if (byteBuf != null) {byte[] buf = new byte[16];ByteBuf len = byteBuf.readBytes(buf, 0, byteBuf.readableBytes());log.debug(new String(buf));}}});}}).bind(8080).sync();

看完这个代码,我们看添加handler时的参数,我们发现"myhandler"被交给了我们自己一开始创建的DefaultEventLoopGroup normalWorkers 来执行。
关系见下图
headtail看做pipelinehandler链的头尾,可视为无意义。
h1代表LoggingHandler
h2代表"myhandler"
在这里插入图片描述

那么这里老师巧妙的引出了pipeline处理过程中的handler的切换,因为两个handler分别是两个不同的EventLoop去执行,就需要一个执行完后交给另一个EventLoop去执行。然后引出了源码,比较容易让人接受,理解。

//handler换人源码
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);// 下一个 handler 的事件循环是否与当前的事件循环是同一个线程EventExecutor executor = next.executor();// 是,直接调用if (executor.inEventLoop()) {next.invokeChannelRead(m);} // 不是,将要执行的代码作为任务提交给下一个事件循环处理(换人)else {executor.execute(new Runnable() {@Overridepublic void run() {next.invokeChannelRead(m);}});}
}
  • 如果两个 handler 绑定的是同一个线程(EventLoop),那么就直接调用
  • 否则,把要调用的代码封装为一个任务对象,由下一个 handler 的线程来调用

NioEventLoop 处理普通任务与定时任务

NioEventLoop还可以执行普通任务和定时任务

//普通任务
NioEventLoopGroup nioWorkers = new NioEventLoopGroup(2);
log.debug("server start...");
Thread.sleep(2000);
nioWorkers.execute(()->{log.debug("normal task...");
});//定时任务
NioEventLoopGroup nioWorkers = new NioEventLoopGroup(2);
log.debug("server start...");
Thread.sleep(2000);
nioWorkers.scheduleAtFixedRate(() -> {log.debug("running...");
}, 0, 1, TimeUnit.SECONDS);

结语

仅仅说使用的话内容好像不多。
api使用的话还要之后自己进行网络程序的编写,学习过程中估计很难记住。还是要学完去实践才能熟练使用。
下篇应该是Netty的Future与Promise,或者Netty Channel相比于NIO的有什么不同(这块估计要看下书,课上没咋提)。

后续会有文章单独说明ServerBootstrap类的一些方法。

感谢阅读,欢迎批评指正。

相关文章:

netty入门-3 EventLoop和EventLoopGroup,简单的服务器实现

文章目录 EventLoop和EventLoopGroup服务器与客户端基本使用增加非NIO工人NioEventLoop 处理普通任务与定时任务 结语 EventLoop和EventLoopGroup 二者大概是什么这里不再赘述&#xff0c;前一篇已简述过。 不理解也没关系。 下面会简单使用&#xff0c;看了就能明白是什么 这…...

通信原理-思科实验五:家庭终端以太网接入Internet实验

实验五 家庭终端以太网接入Internet实验 一实验内容 二实验目的 三实验原理 四实验步骤 1.按照上图选择对应的设备&#xff0c;并连接起来 为路由器R0两个端口配置IP 为路由器R1端口配置IP 为路由器设备增加RIP&#xff0c;配置接入互联网的IP的动态路由项 5.为路由器R1配置静…...

【Vue】vue概述

1、简介 Vue.js&#xff08;简称Vue&#xff09;是一款用于构建用户界面的渐进式JavaScript框架。由前Google高级软件工程师尤雨溪&#xff08;Evan You&#xff09;于2014年创建&#xff0c;是一个独立且社区驱动的开源项目。Vue.js基于标准的HTML、CSS和JavaScript&#xff…...

Docker use experience

#docker command docker load -i <镜像文件.tar> docker run -it -d --name 容器名 -p 宿主机端口:容器端口 -v 宿主机文件存储位置:容器内文位置 镜像名:Tag /bin/bash docker commit -m"提交的描述信息" -a"作者" 容器ID 要…...

Android平台RTSP|RTMP直播播放器技术接入说明

技术背景 大牛直播SDK自2015年发布RTSP、RTMP直播播放模块&#xff0c;迭代从未停止&#xff0c;SmartPlayer功能强大、性能强劲、高稳定、超低延迟、超低资源占用。无需赘述&#xff0c;全自研内核&#xff0c;行业内一致认可的跨平台RTSP、RTMP直播播放器。本文以Android平台…...

数据结构——栈(顺序结构)

一、栈的定义 栈是一种数据结构&#xff0c;它是一种只能在一端进行插入和删除操作的特殊线性表。这一端被称为栈顶&#xff0c;另一端被称为栈底。栈按照后进先出&#xff08;LIFO&#xff09;的原则进行操作&#xff08;类似与手枪装弹后射出子弹的顺序&#xff09;。在计算…...

速盾:cdn能防御ddos吗?

CDN&#xff08;内容分发网络&#xff09;是一种广泛应用于互联网中的技术&#xff0c;它通过将内容分发到全球各地的服务器上&#xff0c;以提高用户在访问网站时的加载速度和稳定性。然而&#xff0c;CDN是否能够有效防御DDoS&#xff08;分布式拒绝服务&#xff09;攻击是一…...

分享 2 个 .NET EF 6 只更新某些字段的方法

前言 EF 更新数据时&#xff0c;通常情况下&#xff0c;是更新全部字段的&#xff0c;但实际业务中&#xff0c;更新全部字段的情况其实很少&#xff0c;一般都是修改其中某些字段&#xff0c;所以为了实现这个目标&#xff0c;很多程序员通常会这样作&#xff1a; 先从数据库…...

vs code解决报错 (c/c++的配置环境 远端机器为Linux ubuntu)

参考链接&#xff1a;https://blog.csdn.net/fightfightfight/article/details/82857397 https://blog.csdn.net/m0_38055352/article/details/105375367 可以按照步骤确定那一步不对&#xff0c;如果一个可以就不用往下看了 目录 一、检查一下文件扩展名 二、安装扩展包并…...

08 字符串和字节串

使用单引号、双引号、三单引号、三双引号作为定界符&#xff08;delimiter&#xff09;来表示字符串&#xff0c;并且不同的定界符之间可以相互嵌套。 很多内置函数和标准库对象也都支持对字符串的操作。 x hello world y Python is a great language z Tom said, "Le…...

vue使用mavonEditor(流程图、时序图、甘特图实现)

mavonEditor 安装mavonEditor $ npm install mavon-editor --save使用 // 全局注册import Vue from vueimport mavonEditor from mavon-editorimport mavon-editor/dist/css/index.css// useVue.use(mavonEditor)new Vue({el: #main,data() {return { value: }}})//局部使用…...

Java实现短信验证码服务

1.首先这里使用的是阿里云的短信服务。 package com.wzy.util;; import cn.hutool.captcha.generator.RandomGenerator; import com.aliyun.dysmsapi20170525.Client; import com.wzy.entity.Ali; import org.springframework.stereotype.Component;/*** Author: 顾安* Descri…...

python中的线程

线程 线程概念 线程 在一个进程的内部, 要同时干多件事, 就需要同时运行多个"子任务", 我们把进程内的这些"子任务"叫做线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中, 是进程的实际运作单位。一条线程指的是进程中一个单一顺序的控制流…...

hcip学习 多实例生成树,VRRP工作原理

一、STP 和 RSTP 解决了什么问题 1、STP&#xff1a;解决了在冗余的二层网络中所出现的环路问题 2、RSTP&#xff1a;在 STP 的基础上&#xff0c;解决了 STP 收敛速度慢的问题&#xff0c;引入了一些 STP 保护机制&#xff0c;使其网络更加稳定 二、MSTP 针对 RSTP 的改进 …...

Docker搭建群晖

Docker搭建群晖 本博客介绍在docker下搭建群晖 1.编辑docker-compose.yml文件 version: "3" services:dsm:container_name: dsmimage: vdsm/virtual-dsm:latestenvironment:DISK_SIZE: "16G"cap_add:- NET_ADMIN ports:- 8080:50…...

【java】BIO,NIO,多路IO复用,AIO

在Java中&#xff0c;处理I/O操作的模型主要有四种&#xff1a;阻塞I/O (BIO), 非阻塞I/O (NIO), 异步I/O (AIO), 以及IO多路复用。下面详细介绍这四种I/O模型的工作原理和应用场景。 1. 阻塞I/O (BIO) 工作原理 阻塞I/O是最传统的I/O模型。在这种模型中&#xff0c;当一个线…...

服务器怎样减少带宽消耗的问题?

择业在使用服务器的过程中会消耗大量的带宽资源&#xff0c;而减少服务器的带宽消耗则可以帮助企业降低经济成本&#xff0c;同时还能够提高用户的访问速度&#xff0c;那么服务器怎样能减少带宽的消耗呢&#xff1f;本文就来带领大家一起来探讨一下吧&#xff01; 企业可以选择…...

linux 报错:bash: /etc/profile: 行 32: 语法错误:未预期的文件结束符

目录 注意错误不一定错在最后一行 i进入编辑 esc退出编辑 &#xff1a;wq 保存编辑退出 &#xff1a;q&#xff01;不保存退出 if [ $# -eq 3 ] then if [ ! -e "$1" ]; then miss1 $1 elif [ ! -e "$2" -a ! -e "$3" ]; then miss2and3…...

MySQL练习(5)

作业要求&#xff1a; 实现过程&#xff1a; 一、触发器 &#xff08;1&#xff09;建立两个表&#xff1a;goods&#xff08;商品表&#xff09;、orders&#xff08;订单表&#xff09; &#xff08;2&#xff09;在商品表中导入商品记录 &#xff08;3&#xff09;建立触发…...

泛型新理解

1.创建三个类&#xff0c;并写好对应关系 package com.jmj.gulimall.study;public class People { }package com.jmj.gulimall.study;public class Student extends People{ }package com.jmj.gulimall.study;public class Teacher extends People{ }2.解释一下这三个方法 pub…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...

【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架

文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理&#xff1a;检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目&#xff1a;RankRAG&#xff1a;Unifying Context Ranking…...