Netty:服务端通过ServerBootstrap的childHandler函数设置处理客户端的ChannelHandler

news2024/11/18 19:51:48

说明

  • 服务端通过io.netty.bootstrap.ServerBootstrap启动,ServerBootstrap的 childHandler(ChannelHandler childHandler)函数用于增加处理客户端的ChannelHandler。
  • 这个childHandler一般是ChannelInitializer的子类,用于配置ChannelPipeline,在ChannelPipeline中增加处理这个客户端的ChannelHandler。一个ChannelPipeline中通常添加多个ChannelHandler。
  • 每当一个新的客户端接入进来,服务端都会针对该客户端创建一新的Channel,对应地,创建新的ChannelPipeline、在ChannelPipeline中增加ChannelHandler。
  • 当完成ChannelPipeline的启动配置后,ChannelInitializer会自己删除自己。
  • 当客户端断开和服务端的连接后,服务端会删除给该客户端服务的Channel、ChannelPipeline、ChannelHandler。

示例

服务端代码片段

package com.thb.power.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * 服务端的主函数
 * @author thb
 *
 */
public class MainStation {
	
	static final int PORT = Integer.parseInt(System.getProperty("port", "22335"));

	public static void main(String[] args) throws Exception {
		// 配置服务器
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap b =  new ServerBootstrap();
			b.group(bossGroup, workerGroup)
			 .channel(NioServerSocketChannel.class)
			 .option(ChannelOption.SO_BACKLOG, 100)
			 .handler(new LoggingHandler(LogLevel.INFO))
			 .childHandler(new MainStationInitializer());
			
			// 启动服务端
			ChannelFuture f = b.bind(PORT).sync();
			
			// 等待直到server socket关闭
			f.channel().closeFuture().sync();
		} finally {
			// 关闭所有event loops以便终止所有的线程
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}

}
package com.thb.power.server;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class MainStationInitializer extends ChannelInitializer<SocketChannel> {

	 @Override
	 public void initChannel(SocketChannel ch) throws Exception {
		 ChannelPipeline p = ch.pipeline();		
		 
		 p.addLast(new LoggingHandler(LogLevel.INFO));
		 p.addLast(new ServerHandler());
		 
		 System.out.println("MainStationInitializer.initChannel is invoked");
	 }
}
package com.thb.power.server;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ServerHandler extends ChannelInboundHandlerAdapter {

	@Override
	public void handlerAdded(ChannelHandlerContext ctx) {
		System.out.println(ctx.handler() + " added");		
	}
	
	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) {
		System.out.println(ctx.handler() + " removed");
	}
}

启动服务端

在这里插入图片描述
从上面输出可以看出,服务端已经正常启动。

启动第一个客户端、观察服务端的输出

在这里插入图片描述
从上面服务端新增的输出可以看出,第一个客户端连接上来,ServerHandler的一个实例被增加进来(其实是增加到处理第一个客户端的Channel对应的ChannelPipeline中),MainStationInitializer的initChannel函数被执行。MainStationInitializer是ChannelInitializer的子类。

启动第二个客户端、观察服务端的输出

第二个客户端连接上来,服务端新增如下输出:
在这里插入图片描述

从上面服务端新增的输出可以看出,第二个客户端连接上来,ServerHandler的另外一个实例被增加进来(其实是增加到处理第二个客户端的Channel对应的ChannelPipeline中),MainStationInitializer的initChannel函数被执行。不要忘了,MainStationInitializer也是一个ChannelHandler。

退出第一个客户端,观察服务端的输出

在第一个客户端的窗口按Ctrl c,退出第一个客户端。
服务端新增如下输出:
在这里插入图片描述
从上面新增的输出可以看出,ServerHandler的第1个实例被移除。

退出第二个客户端,观察服务端的输出

在第二个客户端的窗口按Ctrl c,退出第二个客户端。
服务端新增如下输出:
在这里插入图片描述
从上面新增的输出可以看出,ServerHandler的第2个实例被移除。

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

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

相关文章

GD32F103VE串口与DMA传输

GD32F103VE串口与DMA传输&#xff0c;本测试采用的的串口1和DMA0之间的数据传输&#xff0c;然后通过RS485和其它设备进行数据交换&#xff0c;没有采用任何中断参与。 GD32F103VE的DMA0请求映射到串口&#xff1a; 1&#xff0c;USART0_RX映射到DMA0的通道4&#xff0c;USART…

springboot 多模块 每个模块进行单独打包

springboot项目目录结构 打包模块需要进行的配置 配置文件引入打包插件 <build><finalName>api</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifac…

APT80DQ40BG-ASEMI快恢复二极管APT80DQ40BG

编辑&#xff1a;ll APT80DQ40BG-ASEMI快恢复二极管APT80DQ40BG 型号&#xff1a;APT60DQ20BG 品牌&#xff1a;ASEMI 封装&#xff1a;TO-3P 恢复时间&#xff1a;≤50ns 正向电流&#xff1a;80A 反向耐压&#xff1a;400V 芯片个数&#xff1a;双芯片 引脚数量&…

MySQL|查看事务加锁情况

文章目录 使用information_schema数据库中的表获取锁信息INNODB_TRXINNODB_LOCKSINNODB_LOCK_WAITS 使用SHOW ENGINE INNODB STATUS获取信息补充 使用information_schema数据库中的表获取锁信息 在information_schema数据库中&#xff0c;有几个与事务和锁紧密相关的表 INNOD…

回归预测 | MATLAB实现K折交叉验证GRNN广义回归神经网络多输入单输出回归预测

回归预测 | MATLAB实现K折交叉验证GRNN广义回归神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现K折交叉验证GRNN广义回归神经网络多输入单输出回归预测效果一览基本介绍研究内容程序设计参考资料效果一览 基本介绍 回归预测 | MATLAB实现K折交叉验证GRNN广义回归神经…

MySQL高阶知识点(一) 一条 SQL查询语句是如何被执行的

一条 SQL查询语句是如何被执行的 MySQL 的基本架构示意图如下所示&#xff1a;

MySQL分析查询语句Explain

1概述 ​ 定位了查询慢的SQL之后&#xff0c;就可以使用EXPLAIN或者DESCRIBE工具做针对性的分析查询。两者使用方法相同&#xff0c;并且分析结果也是相同的。 ​ MySQL中有专门负责SQL语句优化的优化器模块&#xff0c;主要功能是计算分析系统中收集到的统计信息&#xff0c…

生信豆芽菜-limma差异分析使用说明

网站&#xff1a;http://www.sxdyc.com/diffLimmaAnalyse 一、limma简介 什么是limma&#xff1f; 首先要明白&#xff0c;不管哪种差异分析&#xff0c;其本质都是广义线性模型。 limma也是广义线性模型的一种&#xff0c;其对每个gene的表达量拟合一个线性方程。 limma的分析…

模拟实现消息队列项目(系列8) -- 实现MqClient

目录 前言 1. 创建ConnectionFactory 2. Connection 和 Channel 的定义 2.1 Connection 2.2 Channel 3. 封装请求响应读写操作 3.1 写入请求 3.2 读取响应 3.3 Connection中创建Channel 4. 封装发送请求的操作 4.1 创建Channel 4.2 阻塞等待服务器响应 4.3 添加响应信息到 basi…

【构造】CF1798 D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 首先如果 a 全是 00&#xff0c;那么显然无解。 否则考虑从左到右构造新数列&#xff0c;维护新数列的前缀和 s。 如果 s≥0&#xff0c;则在剩余未加入的数中随便选择一个非正数添加到新数列末尾。如果 s<…

Semantic Kernel 入门系列:Memory内存

了解的运作原理之后&#xff0c;就可以开始使用Semantic Kernel来制作应用了。 Semantic Kernel将embedding的功能封装到了Memory中&#xff0c;用来存储上下文信息&#xff0c;就好像电脑的内存一样&#xff0c;而LLM就像是CPU一样&#xff0c;我们所需要做的就是从内存中取出…

视频声音怎么转换成文字?这四种转换方法很简单

将视频声音转换成文字的好处不仅仅限于方便记录、保存和查阅视频内容。它还可以大大提高视频内容的可访问性和可搜索性&#xff0c;使得非母语人士、听力障碍者等人群更容易理解视频内容&#xff0c;并且可以更快速地找到相关信息。此外&#xff0c;将视频声音转换成文字还可以…

ArcGISPro随机森林自动化调参分类预测模型展示

更改ArcGISPro的python环境变量请参考文章 ArcGISPro中如何使用机器学习脚本_Z_W_H_的博客-CSDN博客 脚本文件如下 点击运行 结果展示 负类预测概率 正类预测概率 二值化概率 文件夹&#xff08;模型验证结果&#xff09; 数据集数据库 ROC曲线 由于个人数据量太少所以…

工业4.0:欢迎来到智能制造

制造业正在经历一场被称为“工业4.0”的全新技术革命&#xff0c;这场革命将数字化、网络化、智能化和自动化技术融合在一起&#xff0c;旨在打造高质、高效、高产且可持续的智能工厂。工业4.0将彻底改变产品制造的方式&#xff0c;颠覆我们对制造业的传统认知。 什么是工业4.…

APP电话管家在各行业的应用

目前语音呼叫在各行业广泛应用&#xff0c;不管是电话销售也好&#xff0c;还是客户呼入咨询也好&#xff0c;部署呼叫中心对于业务提升&#xff0c;还是很有效率的。但是随着使用的行业越来越多&#xff0c;有些行业属性所在&#xff0c;需要有便于携带&#xff0c;企业管理可…

无涯教程-Perl - exp函数

描述 此函数将e(自然对数底数)返回到EXPR的幂。如果省略EXPR,则给出exp($_)。 语法 以下是此函数的简单语法- exp EXPRexp返回值 此函数不返回任何值。 Perl 中的 exp函数 - 无涯教程网无涯教程网提供描述此函数将e(自然对数底数)返回到EXPR的幂。如果省略EXPR,则给出exp(…

Flowable-结束事件-终止结束事件

目录 定义图形标记XML内容视频教程 定义 当流程到达终止结束事件时&#xff0c;该流程将终止。当流程实例有多个流程分支被激活时&#xff0c;当有一个 分支到达终止结束事件时&#xff0c;所有其它流程分支也立即结束。在 flowable 中&#xff0c;当流程执行到达终止结 束事件…

轻松抓取网页内容!API助力开发者,快速数据采集

在如今这个信息爆炸的时代&#xff0c;人们需要从各种渠道获取数据来支持自己的业务需求。而对于开发者们来说&#xff0c;如何快速、准确地从互联网上抓取所需的数据也成为了一项重要的技能。而抓取网页内容 API 则是一种能够帮助开发者轻松实现数据抓取的工具。 一、什么是抓…

springboot mongo 使用

nosql对我来说&#xff0c;就是用它的变动列&#xff0c;如果列是固定的&#xff0c;我为什么不用mysql这种关系型数据库呢&#xff1f; 所以&#xff0c;现在网上搜出来的大部分&#xff0c;用实体类去接的做法&#xff0c;并不适合我的需求。 所以&#xff0c;整理记录一下…

Vue命名规范

JS文件命名 一般采用的是小驼峰命名法&#xff0c;如 pieChartHelp 第一个单词小写&#xff0c;其他单词首字母大写 Components 文件命名 一般采用的是大驼峰命名法&#xff0c;如PieChart 所有单词的首字母大写 常量命名 一般全部大写&#xff0c;每个单词使用分隔符隔开&…