Netty2

文章目录

  • Netty2
    • Netty入站与出站机制
    • Netty的handler链的调用机制

Netty2

Netty入站与出站机制

基本说明
1)netty的组件设计:Netty的主要组件有Channel,EventLoop,ChannelFuture,ChannelHandler,ChannelPipe等。
2)ChannelHandler 充当了处理入站和出站数据的应用程序逻辑的容器。例如,实现 ChannelInboundHandler 接口(或 ChannelInboundHandlerAdapter),你就可以接收入站事件和数据,这些数据会被业务逻辑处理。当要给客户端发送响应时,也可以从 ChannelInboundHandler 冲刷数据。业务逻辑通常卸载一个或者多个 ChannelInboundHandler 中。ChannelOutboundHandler 原理一样,只不过它是用来处理出站数据的。
3)ChannelPipeline 提供了 ChannelHandler 链的容器。以客户端应用程序为例,如果事件的运动方向是从客户端到服务端的,那么我们称这些事件为出站的,即客户端发送服务端的数据会通过 pipeline 中的一系列 ChannelOutboundHandler,并被这些 Handler 处理,反之则称为入站的。

在这里插入图片描述

编码解码器
1)当 Netty 发送或者接收一个消息的时候,就将会发生一次数据转换。入站消息会被解码:从字节转换为另一种格式(比如 java 对象);如果是出站消息,它会被编码成字节。
2)Netty 提供一系列实用的编解码器,他们都实现了 ChannelInboundHandler 或者 ChannelOutboundHandler 接口。在这些类中,channelRead 方法已经被重写了。已入站为例,对于每个从入站 Channel 读取的消息,这个方法会被调用。随后,它将调用由解码器所提供的 decode() 方法进行解码,并将已经解码的字节转发给 ChannelPipeline 中的下一个 ChannelInboundHandler。

解码器ByteToMessageDecoder
1)关系继承图,如下图:
在这里插入图片描述
2)由于不可能知道远程节点是否会一次性发送一个完整的信息,tcp有可能出现粘包拆包的问题,这个类会对入站数据进行缓冲,直到它准备好被处理。
3)关于ByteToMessageDecoder实例分析

public class ToIntegerDecoder extends ByteToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {if(in.readableBytes() >= 4){out.add(in.readInt());}}
}

注意ByteToMessageDecoder是一个解码器,除了这个解码器,还有一个编码器叫做MessageToByteEncoder。

实例说明:

  • 这个例子,每次入站从 ByteBuf 读取4字节,将其解码为一个 int,然后将它添加到下一个 List 中。当没有更多元素可以被添加到该 List 中,它的内容将会发送给下一个 ChannelInboundHandler。int 在被添加到 List 中时,会被自动装箱为 Integer。在调用 readInt() 方法前必须验证所输入的 ByteBuf 是否具有足够的数据。
  • decode执行分析图。在这里插入图片描述

Netty的handler链的调用机制

要求:使用自定义的编码器和解码器来说明Netty的handler调用机制。
客户端发送long -> 服务器
服务端发送long->客户端

结果:数据在客户端和服务端之间传输的时候是通过二进制文件的形式传输的。客户端会先调用它的业务处理ClientHandler,然后会调用编码器Handler,接着把数据传输到Socket中,再由Socket把数据传输到服务器中;服务器接收到Socket中的数据之后,会先调用解码器Handler进行解码,然后调用它自己的ServerHandler进行业务处理,接着会把数据返回给客户端,会把这些数据编码,因此会执行编码器Handler,然后把数据传输到Scoket里面,再通过Scoket把数据传输给客户端,客户端拿到数据之后先解码,先调用解码处理器进行解码,然后再调用ClientHandler处理器进行客户端业务处理。整体流程图如下图:
在这里插入图片描述
编码器和解码器代码如下:

/*** @author xuan* @create 2023/9/19* 编码器*/
public class MyLongToByteEncoder extends MessageToByteEncoder<Long> {@Overrideprotected void encode(ChannelHandlerContext ctx, Long msg, ByteBuf out) throws Exception {System.out.println("MyLongToByteEncoder 的 encode()方法被调用");System.out.println("msg = " + msg);out.writeLong(msg);}
}/*** @author xuan* @create 2023/9/19* 解码器*/
public class MyByteToLongDecoder extends ByteToMessageDecoder {/*** decode 会根据接收的数据,被调用多次,知道确定没有新的元素被添加到list,或者是Bytebuf 没有更多的可读字节为止* 如果 list out 不为空,就会将list的内容传递给下一个 channelInboundHandler 处理,该处理器的方法也会被调用多次** @param ctx 上下文* @param in 入站的 ByteBuf* @param out List 集合,将解码后的数据传给下一个 handler 处理* @throws Exception*/@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {System.out.println("MyByteToLongDecoder 的 decode()方法被调用");// 因为 long 是 8 个字节,需要判断有 8 个字节,才能读取一个 longif(in.readableBytes() >= 8){out.add(in.readLong());}}
}

服务端代码如下:

/*** @author xuan* @create 2023/9/19*/
public class MyServer {public static void main(String[] args) throws InterruptedException {NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);NioEventLoopGroup workerGroup = new NioEventLoopGroup(8);try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new MyServerInitializer());ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();channelFuture.channel().closeFuture().sync();}finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}}
/*** @author xuan* @create 2023/9/19*/
public class MyServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// 入站的 handler 进行解码pipeline.addLast(new MyByteToLongDecoder());pipeline.addLast(new MyLongToByteEncoder());pipeline.addLast(new MyServerHandler());}
}
/*** @author xuan* @create 2023/9/19*/
public class MyServerHandler extends SimpleChannelInboundHandler<Long> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, Long msg) throws Exception {System.out.println("从客户端" + ctx.channel().remoteAddress() + "读取到的数据到long " + msg);// 给客户端发送一个 longctx.writeAndFlush(123L);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

客户端代码如下:

/*** @author xuan* @create 2023/9/19*/
public class MyClient {public static void main(String[] args) throws InterruptedException {NioEventLoopGroup group = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new MyClientInitializer());ChannelFuture channelFuture = bootstrap.connect("localhost", 8080).sync();channelFuture.channel().closeFuture().sync();}finally {group.shutdownGracefully();}}
}
/*** @author xuan* @create 2023/9/19*/
public class MyClientInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();//加入一个出站的handler,对数据进行一个编码pipeline.addLast(new MyLongToByteEncoder());pipeline.addLast(new MyByteToLongDecoder());//加入一个自定义的handler,处理业务逻辑pipeline.addLast(new MyClientHandler());}
}
/*** @author xuan* @create 2023/9/19*/
public class MyClientHandler extends SimpleChannelInboundHandler<Long> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, Long msg) throws Exception {System.out.println("服务器的ip=" + ctx.channel().remoteAddress());System.out.println("服务器回送的消息:" + msg );}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("MyClientHandler 发送数据");ctx.writeAndFlush(123456L);// 分析// 1. "abcdabcdabcdabcd" 是16个字节// 2. 该处理器的前一个 handler 是 MyLongToByteEncoder// 3. MyLongToByteEncoder 父类是 MessageToByteEncoder// 4. 父类 MessageToByteEncoder 中 acceptOutboundMessage(msg) 会判断当前 msg 是不是应该处理的类型,如果是就处理,不是就跳过// 5. 编写 Encoder 时要注意传入的数据类型和处理的数据类型需要一致
//        ctx.writeAndFlush(Unpooled.copiedBuffer("abcdabcdabcdabcd", CharsetUtil.UTF_8));}
}

几个要点说明,如下图:
在这里插入图片描述
编码的时候直接把Long类型数据写入即可,会自动的转换为byte二进制类型,如下图:
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SaaS架构C/S检验科LIS系统源码: 检验申请、标本编号、联机采集

适用于医院检验科实际需要的LIS管理系统, 实现检验业务全流程的计算机管理。从检验申请、标本编号、联机采集、中文报告单的生成与打印、质控图的绘制和数据的检索与备份。通过将所有仪器自身提供的端口与科室LIS系统中的工作站点连接,实现与医院HIS系统的对接。 通过门诊医生和…

如何使用ArcGIS中的Arcmap进行矢量和栅格数据裁剪?

在地理信息系统(GIS)中&#xff0c;我们经常需要处理各种空间数据&#xff0c;而矢量和栅格数据是最常见的两种数据类型。有时候&#xff0c;我们需要对数据进行裁剪&#xff0c;以提取出我们需要的特定区域的数据。本文将介绍如何使用ArcGIS中的Arcmap软件对矢量和栅格数据进行…

选择渲染农场的几个标准

随着电影、电视剧等影视作品的制作越来越依赖于计算机特效&#xff0c;渲染农场的使用也变得越来越普遍。渲染农场是一种利用大量计算机图形处理器&#xff08;GPU&#xff09;来加速渲染过程的服务。在选择渲染农场时&#xff0c;有几个标准可以帮助您确定哪个农场是适合您的项…

Unity3D C# 反射与特性的配合使用

需求分析 情况&#xff1a; 假如我们是一个动物园的管理员&#xff0c;我们需要统计园内的所有动物和动物的行为。 举例&#xff1a; 现在园区内有猫、狗和鸡。猫对应的行为是喵喵喵和卖萌&#xff0c;狗对应狗吠和干饭&#xff0c;鸡对应篮球和打鸣那么这时候我要统计这些&a…

在qml中将一个16进制表示的颜色加上透明度

在qml中&#xff0c;我们在指定控件的颜色时&#xff0c;可以直接通过16进制的字符串来表示&#xff0c;比如"#ff0000"; 这种方式也比较符合UI设计人员的使用习惯。 但是假如要在此颜色的基础上&#xff0c;加个透明度的话&#xff0c;就要重新计算一番&#xff0c;比…

腾讯云2核4G服务器5M带宽 218元一年 优惠价格明细表

腾讯云2核4G服务器5M带宽可以选择轻量应用服务器或云服务器ECS&#xff0c;轻量2核4G5M带宽服务器218元一年&#xff1a; 腾讯云2核4G服务器5M带宽收费 腾讯云2核4G服务器可以选择轻量应用服务器或者ECS云服务器&#xff0c;云服务器ECS是专业级云服务器&#xff0c;大多数使用…

deepin V23通过flathub安装steam畅玩游戏

deepin V23缺少32位库&#xff0c;在星火商店安装的steam,打开报错&#xff0c;无法使用&#xff01; 通过flathub网站安装steam,可以正常使用&#xff0c;详细教程如下&#xff1a; flathub网址&#xff1a;主页 | Flathub 注意&#xff1a;flathub下载速度慢&#xff0c;只…

小程序自定义tabbar

前言 使用小程序默认的tabbar可以满足常规开发&#xff0c;但是满足不了个性化需求&#xff0c;如果想个性化开发就需要用到自定义tabbar,以下图为例子 一、在app.json配置 先按照以往默认的形式配置&#xff0c;如果中间的样式特殊则不需要配置 "tabBar": {&qu…

自动清洁离子风机的主要功能

除静电离子风机有好几种类型&#xff0c;其功能、外观、材质尺寸都大不相同&#xff0c;下面介绍的是自清洁清洁型的离子风机。 离子风机具有自动清洁&#xff0c;免保养&#xff0c;除静电效果长期稳定的特点。其主要特征有&#xff1a;1.自动清洁&#xff1a;可根据环境在0-9…

华为云云耀云服务器L实例评测|StackEdit中文版在线Markdown笔记工具

华为云云耀云服务器L实例评测&#xff5c;StackEdit中文版在线Markdown笔记工具 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 应用场景1.3 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 StackEdit 中文版3.1 StackEdit 介绍3.2 环…

学习路之PHP--laravel postman 提交表单出现419错误

问题图片 解决&#xff1a; 白名单 有时候你可能希望设置一组不需要 CSRF 保护的 URL 。例如&#xff0c;如果你正在使用 Stripe 处理付款并使用了他们的 webhook 系统&#xff0c;你会需要从 CSRF 的保护中排除 Stripe webhook 处理程序路由&#xff0c;因为 Stripe 不知道要发…

最新版WPS 2023 加载Zotero方法

安装wps2019vba.exe&#xff0c;获取链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1eeoc6Tmwyzxh3n1MFQTVeA 提取码&#xff1a;6431 –来自百度网盘超级会员V8的分享 打开WPS的工具的加载项 添加文件路径&#xff0c;我的在&#xff1a; C:\Users\Administrat…