网站开发属于什么部门,能在线做英语题目的网站,织梦模板自适应,wordpress删除媒体库功能【README】
1.本文源代码总结自 B站《netty-尚硅谷》#xff1b;2.本文部分内容总结自 https://www.baeldung.com/netty3.本文主要介绍了通道管道中多个入栈处理器与多个出站处理器如何执行#xff1f;并用代码演示执行顺序#xff1b;
补充#xff1a;文末附带了 log4j整…【README】
1.本文源代码总结自 B站《netty-尚硅谷》2.本文部分内容总结自 https://www.baeldung.com/netty3.本文主要介绍了通道管道中多个入栈处理器与多个出站处理器如何执行并用代码演示执行顺序
补充文末附带了 log4j整合到netty的配置 【1】事件与处理器
1概述
netty使用了一种事件驱动的应用范式因此数据处理的管道是一个经过处理器的事件链。事件和处理器可以关联到 inbound入站 与 outbound出站 数据流。
2入站事件如下inbound
channel通道激活与失活activation and deactivation读操作事件异常事件用户事件
3出站事件很简单如下outbound
打开与关闭连接写出或刷新缓冲区数据
4netty应用包含许多网络和应用逻辑事件及它们的处理器。
通道事件处理器的基本接口是 ChannelHandler其子类有 ChannelOutboundHandler 和 ChannelInboundHandler 【2】处理器链
1入站和出栈事件都会经过预设的处理器链多个处理器
即入站事件经过 入站处理器出站事件经过出站处理器多个处理器形成一个链或管道
2处理器举例
网络传输全是字节形式而业务逻辑处理是对象形式所以需要编码器把对象转字节需要解码器把字节转对象 ByteToMessageDecoder 字节转消息对象解码器MessageToByteEncoder 消息对象转字节编码器业务逻辑处理器如加工统计入库消息转发等
3以客户端服务器模式介绍入站与出站处理器的事件处理过程 【图解】 客户端的处理器有
解码处理器编码处理器客户端业务处理器
服务端的处理器有
解码处理器编码处理器服务器业务处理器
补充多个处理器封装到通道管道 ChannelPipeline 【3】处理器链调用机制代码实现
1需求描述
自定义编码器和解码器实现客户端与服务器间的数据传输
2通道管道ChannelPipeline 可以封装多个处理器其处理器执行顺序特别重要前后关系特别重要如入栈解码处理器要第1个执行又如出站编码器要最后一个执行否则客户端与服务器将无法通信因为事件或数据要经过所有的处理器类似于如下
for (event event : events) {handler1(event);handler2(event);handler3(event);
}
3入站与出站处理器执行顺序
3.1服务器初始化器添加处理器到管道 3.2客户端初始化器 【3.1】服务器
1服务器用于监听网络端口处理请求
/*** Description 测试handler链的服务器* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class NettyServerForHandlerChain80 {public static void main(String[] args) throws InterruptedException {EventLoopGroup bossGroup new NioEventLoopGroup(1);EventLoopGroup workerGroup new NioEventLoopGroup();try {ServerBootstrap serverBootstrap new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new NettyServerInitializer()); // 自定义一个初始化类// 自动服务器ChannelFuture channelFuture serverBootstrap.bind(8089).sync();System.out.println(服务器启动成功);// 监听关闭channelFuture.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
2通道初始化器把多个处理器添加到通道管道
/*** Description 初始化器* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class NettyServerInitializer extends ChannelInitializerSocketChannel {Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline ch.pipeline();// 入站handler把字节型数据解码为long型
// pipeline.addLast(new MyByte2LongDecoder()); // MyByte2LongDecoder 与 MyByte2LongDecoder2 等价pipeline.addLast(new MyByte2LongDecoder2());// 出站handler, 把long型数据编码为字节(编码器)pipeline.addLast(new MyLong2ByteEncoder());// 添加业务逻辑handlerpipeline.addLast(new NettyServerHandler());System.out.println(NettyServerInitializer.initChannel 执行成功.);}
}
3服务端业务处理器业务逻辑处理
/*** Description nety服务器handler* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class NettyServerHandler extends SimpleChannelInboundHandlerLong {// 被调用多次Overrideprotected void channelRead0(ChannelHandlerContext ctx, Long msg) throws Exception {System.out.println(从客户端 ctx.channel().remoteAddress() 读取到long msg);// 给客户端回送消息ctx.writeAndFlush(98765L);}Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
} 【3.2】客户端
1客户端建立与服务器的连接
/*** Description netty客户端* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class NettyClientForHandlerChain81 {public static void main(String[] args) throws InterruptedException {EventLoopGroup group new NioEventLoopGroup();try {Bootstrap bootstrap new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new NettyClientInitializer()); // 自定义一个初始化类// 连接服务器ChannelFuture channelFuture bootstrap.connect(localhost, 8089).sync();channelFuture.channel().closeFuture().sync();} finally {group.shutdownGracefully();}}
}
2通道初始化器添加多个处理器到通道管道
/*** Description netty客户端初始化器* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class NettyClientInitializer extends ChannelInitializerSocketChannel {Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline ch.pipeline();// 出站handler把long型数据解码为字节型pipeline.addLast(new MyLong2ByteEncoder());// 入站handler把字节型数据解码为long型pipeline.addLast(new MyByte2LongDecoder());// 添加一个自定义handler入站处理业务逻辑pipeline.addLast(new NettyClientHandler());}
}3客户端业务处理器业务逻辑处理
/*** Description 客户端处理器* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class NettyClientHandler extends SimpleChannelInboundHandlerLong {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(NettyClientHandler 发送数据);// 1 分析// 1.1 abcdefgabcdefgab 是16个字节 long型占8个字节所以服务器需要解码2次每次解码8个字节// 1.2 该处理器的前一个handler是 MyLong2ByteEncoder// 1.3 MyLong2ByteEncoder 的父类是 MessageToByteEncoder// 1.4 MessageToByteEncoder.write()方法通过acceptOutboundMessage判断当前msg是否为要处理的数据类型// 若不是则跳过encode方法 否则执行对应的encode 方法处理方法// 客户端发送一个ByteBuf不走Long型编码器ctx.writeAndFlush(Unpooled.copiedBuffer(abcdefgabcdefgab, StandardCharsets.UTF_8));// 客户端发送一个Long走Long型编码器
// ctx.writeAndFlush(123456L); // 发送一个long}
} 【3.3】编码器与解码器处理器
1字节转 Long型的解码器处理器
/*** Description 字节转long的解码器* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class MyByte2LongDecoder extends ByteToMessageDecoder {/*** description decode 会根据接收的数据被调用多次直到确定没有新元素被添加到list为止 或者 ByteBuf没有更多的可读字节为止* 如果list out 不为空就会将list的内容传递给下一个 ChannelInboundHandler* 且下一个 ChannelInboundHandler的处理方法也会被调用多次* param ctx 处 理器上下文* param in 字节输入缓冲* param out 集合把处理后的数据传给下一个 ChannelInboundHandler** return* author xiao tang* date 2022/9/10*/Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, ListObject out) throws Exception {System.out.println(decode解码);// long 8个字节需要判断有8个字节才能读取一个longif (in.readableBytes() 8) {out.add(in.readLong());}}
} 一个 解码器 变体
/*** Description 字节转long的解码器* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class MyByte2LongDecoder2 extends ReplayingDecoder {/*** description decode 会根据接收的数据被调用多次直到确定没有新元素被添加到list为止 或者 ByteBuf没有更多的可读字节为止* 如果list out 不为空就会将list的内容传递给下一个 ChannelInboundHandler* 且下一个 ChannelInboundHandler的处理方法也会被调用多次* param ctx 处 理器上下文* param in 字节输入缓冲* param out 集合把处理后的数据传给下一个 ChannelInboundHandler** return* author xiao tang* date 2022/9/10*/Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, ListObject out) throws Exception {System.out.println(MyByte2LongDecoder2被调用 decode解码);// ReplayingDecoder无需判断字节流是否足够读取内部会进行处理判断
// if (in.readableBytes() 8) { // 无需判断out.add(in.readLong());
// }}
}2Long型转字节的编码器处理器
/*** Description long转字节的编码器* author xiao tang* version 1.0.0* createTime 2022年09月10日*/
public class MyLong2ByteEncoder extends MessageToByteEncoderLong {Overrideprotected void encode(ChannelHandlerContext ctx, Long msg, ByteBuf out) throws Exception {System.out.println(MyLong2ByteEncoder.encode 被调用);System.out.println(MyLong2ByteEncoder msg msg);out.writeLong(msg);}
}【3.4】运行效果
1客户端
decode解码
得到服务器ip localhost/127.0.0.1:8089
收到服务器消息 98765
decode解码
得到服务器ip localhost/127.0.0.1:8089
收到服务器消息 98765
2服务器
MyByte2LongDecoder2被调用 decode解码
从客户端/127.0.0.1:56272读取到long7017280452245743457
MyLong2ByteEncoder.encode 被调用
MyLong2ByteEncoder msg 98765
MyByte2LongDecoder2被调用 decode解码
从客户端/127.0.0.1:56272读取到long7089620625083818338
MyLong2ByteEncoder.encode 被调用
MyLong2ByteEncoder msg 98765 【4】 log4j整合到 netty
1引入log4j maven依赖 dependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion1.2.17/version
/dependency
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.25/version
/dependency
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-log4j12/artifactIdversion1.7.25/versionscopetest/scope
/dependency
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-simple/artifactIdversion1.7.25/versionscopetest/scope
/dependency
2配置log4j
log4j.rootLoggerDEBUG, stdout
log4j.appender.stdoutorg.apache.log4j.ConsoleAppender
log4j.appender.stdout.layoutorg.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern[%p] %C{1} - %m%n
3效果