Netty:ChannelHandler抛出异常,对应的channel被关闭
说明
使用Netty框架构建的socket服务端在处理客户端请求时,每接到一个客户端的连接请求,服务端会分配一个channel处理跟该客户端的交互。如果处理该channel数据的ChannelHandler抛出异常没有捕获,那么该channel会关闭。但服务端和其它客户端的通信不受影响。
代码示例
该示例验证场景:
服务端和客户端建立了正常的连接,服务端给该客户端分配了一个channel。从该channel读取数据的ChannelHandler抛出异常,没有被捕获,导致该channel被关闭,服务端和该客户端的通信中断。但服务端和其它客户端的通信不受影响。
服务端代码片段
package com.thb.power.server;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;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 {private static final Logger logger = LogManager.getLogger();static final int PORT = Integer.parseInt(System.getProperty("port", "22335"));public static void main(String[] args) throws Exception {logger.traceEntry();// 配置服务器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();}logger.traceExit();}}
package com.thb.power.server;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import com.thb.power.constant.PowerConstants;
import com.thb.power.handler.VerifyChecksumHandler;import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;public class MainStationInitializer extends ChannelInitializer<SocketChannel> {private static final Logger logger = LogManager.getLogger();@Overridepublic void initChannel(SocketChannel ch) throws Exception {logger.traceEntry();ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler(LogLevel.INFO));// 用报文开头的字符、结尾的字符作为分隔符,解析成完整的报文 p.addLast(new DelimiterBasedFrameDecoder(PowerConstants.SOCKET_MAX_BYTES_PER_PACKET, true, Unpooled.wrappedBuffer(new byte[] {PowerConstants.SOCKET_END_MARK}),Unpooled.wrappedBuffer(new byte[] {PowerConstants.SOCKET_START_MARK}))); p.addLast(new VerifyChecksumHandler());logger.traceExit();}
}
package com.thb.power.handler;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.util.ReferenceCounted;/*** 验证接收的报文的校验和* @author thb**/
public class VerifyChecksumHandler extends ChannelInboundHandlerAdapter {private static final Logger logger = LogManager.getLogger();@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {logger.traceEntry(); if (msg instanceof ByteBuf) {ByteBuf m = (ByteBuf)msg;logger.info("msg reference count: {}", m.refCnt());// 此处人为构造场景,以便验证抛出异常的情况。将引用计数减少1,执行后,引用计数变为0,读数据会抛异常m.release();m.readByte();logger.info("readableBytes: " + m.readableBytes()); // 将收到的报文的每个字节转换为十六进制打印出来 logger.info(ByteBufUtil.prettyHexDump(m)); } else {// 这个数据不需要向后传递,因为数据已经错误了// 传入的对象msg如果实现了ReferenceCounted接口,那么显式就释放if (msg instanceof ReferenceCounted) {((ReferenceCounted)msg).release();}throw new CorruptedFrameException("received illegal data: not ByteBuf type");}logger.traceExit();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}
}
package com.thb.power.constant;/*** 保存了一些常数* @author thb**/
public final class PowerConstants {/*** 定义了私有构造函数,防止被外部实例化*/private PowerConstants() {}/*** 通信报文的起始符*/public static final byte SOCKET_START_MARK = (byte)0x68;/*** 通信报文的的结束符*/public static final byte SOCKET_END_MARK = (byte)0x16;/*** 每个报文的最大字节数*/public static final short SOCKET_MAX_BYTES_PER_PACKET = 1024;
}
启动服务端
启动客户端,并向服务端发送数据
服务端的ChannelHandler处理数据时抛出了异常,断开了和该客户端的连接
从输出可以看出,服务端处理客户端channel数据的ChannelHandler抛出了异常,服务端终止了和该客户端的连接。
观察客户端的输出
从输出可以看出,客户端终止了和服务端的连接。
服务端可以继续接受新的客户端连接
从输出可以看出,服务端可以正常接受新的客户端的连接
相关文章:

Netty:ChannelHandler抛出异常,对应的channel被关闭
说明 使用Netty框架构建的socket服务端在处理客户端请求时,每接到一个客户端的连接请求,服务端会分配一个channel处理跟该客户端的交互。如果处理该channel数据的ChannelHandler抛出异常没有捕获,那么该channel会关闭。但服务端和其它客户端…...

pytest结合 allure 打标记之的详细使用
前言 前面我们提到使用allure 可以生成漂亮的测试报告,下面就Allure 标记我们做详细介绍。 allure 标记 包含:epic,feature, story, title, testcase, issue, description, step, serverity, link, attachment 常用的标记 allure.feature…...

【linux】2 软件管理器yum和编辑器vim
目录 1. linux软件包管理器yum 1.1 什么是软件包 1.2 关于rzsz 1.3 注意事项 1.4 查看软件包 1.5 如何安装、卸载软件 1.6 centos 7设置成国内yum源 2. linux开发工具-Linux编辑器-vim使用 2.1 vim的基本概念 2.2 vim的基本操作 2.3 vim正常模式命令集 2.4 vim末行…...
Angular中的ActivatedRoute和Router
Angular中的ActivatedRoute和Router解释 在Angular中,ActivatedRoute和Router是两个核心的路由服务。他们都提供可以用来检查和操作当前页面路由信息的方法和属性。 ActivatedRoute ActivatedRoute是一个保存关于当前路由状态(如路由参数、查询参数以…...

Layui精简版,快速入门
目录 LayUI之入门 1.什么是layui 2.layui入门 3.自定义模块 4.用户登录 5.主页搭建 LayUI之动态树 main.jsp main.js LayUI之动态选项卡 1.选项卡 main.jsp main.js 2.用户登录 User.java UserDao.java UserAction.java R.java LayUI之用户管理 1.用户查询…...
SSH远程Ubuntu教程
SSH远程Ubuntu教程 目录 什么是SSH?SSH的优点在Ubuntu上启用SSH服务连接到远程Ubuntu服务器SSH的常用命令 1. 什么是SSH? SSH(Secure Shell)是一种网络协议,用于在不安全的网络中安全地远程登录和执行命令。它使用…...

NPM与外部服务的集成(下)
目录 1、撤消访问令牌 2、在CI/CD工作流中使用私有包 2.1 创建新的访问令牌 持续整合 持续部署 交互式工作流 CIDR白名单 2.2 将令牌设置为CI/CD服务器上的环境变量 2.3 创建并签入特定于项目的.npmrc文件 2.4 令牌安全 3、Docker和私有模块 3.1 背景:运…...

Flask Web开发实战(狼书)| 笔记第1、2章
前言 2023-8-11 以前对网站开发萌生了想法,又有些急于求成,在B站照着视频敲了一个基于flask的博客系统。但对于程序的代码难免有些囫囵吞枣,存在许多模糊或不太理解的地方,只会照葫芦画瓢。 而当自己想开发一个什么网站的时&…...

PHP利用PCRE回溯次数限制绕过某些安全限制实战案例
目录 一、正则表达式概述 有限状态自动机 匹配输入的过程分别是: DFA(确定性有限状态自动机) NFA(非确定性有限状态自动机) 二、回溯的过程 三、 PHP 的 pcre.backtrack_limit 限制利用 例题一 回溯绕过步骤 &…...

读书笔记 |【项目思维与管理】➾ 顺势而动
读书笔记 |【项目思维与管理】➾ 顺势而动 一、企业步入“终结者时代”二、过去成功的经验也许是最可怕的三、做好非重复性的事四、适应客户是出发点五、向知识型企业转变六、速度是决胜条件 💖The Begin💖点点关注,收藏不迷路💖 …...
开发利器:接口代理和接口模拟工具
前端开发过程往往需要和后端对接接口,而且一般开发都是前后端同步开发,这就难免出现接口提供滞后的问题,从而导致我们前端开发 UI 开发完成而无法调试的问题。面对这种问题,一般我们会有很多种方式处理,比如在代码中写一些模拟数据,或者打断点调试,或者用代理工具 Fidde…...

MAVEN利器:一文带你了解MAVEN以及如何配置
前言: 强大的构建工具——Maven。作为Java生态系统中的重要组成部分,Maven为开发人员提供了一种简单而高效的方式来构建、管理和发布Java项目。无论是小型项目还是大型企业级应用,Maven都能帮助开发人员轻松处理依赖管理、编译、测试和部署等…...

解决 adb install 错误INSTALL_FAILED_UPDATE_INCOMPATIBLE
最近给游戏出包,平台要求 v1 签名吧,AS 打包后,adb 执行安装到手机,我用的设备是google pixel6 , android 系统 13, 提示如下: adb install -r v5_android_202308161046.apk Performing Streamed Install a…...
学习Vue:Event Bus 与 Provide/Inject
在Vue.js中,兄弟组件通信是指两个没有直接父子关系的组件之间如何进行数据传递和通信。为了实现兄弟组件通信,我们可以借助Vue的一些特性,如Event Bus和Provide/Inject。让我们一起来深入了解这些方法,并通过实例来看看如何实现兄…...
Java 工具类之JSON key根据ASCII排序
Java按键值字典序排列 参数按照KEY值进行字典序排序(按照KEY值的ASCII码从小到大),并用&作为各参数之间的分隔符将参数拼接成字符串。这里用到了SortedMap,复制以下代码开箱即用~ /*** getSortedString 对参数按照Key进行ASCII排序* param jsonObject 请求参数…...

深兰科技提出新多模态谣言监测模型,刷新世界纪录
近日,深兰科技旗下深兰科技科学院投稿的《基于二部特定事件树的分层表示的谣言检测》(Rumor Detection With Hierarchical Representation on Bipartite Ad Hoc Event Trees)研究论文被全球人工智能领域*期刊《IEEE Transactions on Neural Networks and Learning S…...
【从零学习python 】33.装饰器的作用(二)
文章目录 再议装饰器4. 装饰器(decorator)功能5. 装饰器示例例1:无参数的函数例2:被装饰的函数有参数例3:被装饰的函数有不定长参数例4:装饰器中的return例5:装饰器带参数 进阶案例 再议装饰器 # 定义函数:完成包裹数据 def makeBold(fn):def wrapped():return &qu…...

【自动电压调节器】无功功率控制的终端电压控制研究(Simulink)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

比ChatGPT更强的星火大模型V2版本发布!
初体验 测试PPT生成 结果: 达到了我的预期,只需要微调就可以直接交付,这点比ChatGPT要强很多. 测试文档问答 结果: 这点很新颖,现在类似这种文档问答的AI平台收费都贵的离谱,星火不但免费支持而且效果也…...
Character Animation With Direct3D 读书笔记
角色动画简介 2D动画:循环播放多张图片 3D动画: 骨骼动画、变形动画 DirectX入门 Win32 应用程序 Application类:处理主程序循环,图形设备的初始化 Init:加载资源并创建图形设备Update:更新游戏世界&am…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...