Netty中ctx.writeAndFlush与ctx.channel().writeAndFlush的区别
来源:互联网 发布:mac pdf 导出图片 编辑:程序博客网 时间:2024/05/23 12:39
最近在写netty相关代码,发现writeAndFlush这个方法既可以在ctx上调用,也可以在channel上调用,这两者有什么区别呢,于是就做了一个小实验。具体的代码在最后
Client端
client的handler
这次我们主要在服务端进行实验,因此client端就简单构造一个handler用来接收发来的信息并传送回去,以形成和server通信的态势。
public class C_I_1 extends ChannelInboundHandlerAdapter{ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Number n = (Number)msg; System.out.println("C in 111 get num = " + n.getNum()); n.add(); ctx.writeAndFlush(n); }}
这里构建了一个Number实体类,就是存一个数而已。add方法就是让类的数加一。client的handler就是这个了。
client构建
这就是日常的netty客户端的构建方法,具体的怎么绑定什么的不讲了。然后我们在连接服务端之后向服务端发出一个数字1
public class Client { static String host = "127.0.0.1"; static int port = 10010; public static void main(String[] args) { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY,true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //这里一定要加入这两个类,是用来给object编解码的,如果没有就无法传送对象 //并且,实体类要实现Serializable接口,否则也无法传输 ch.pipeline().addLast(new ObjectEncoder()); ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度 ch.pipeline().addLast(new C_I_1()); } }); try { Number n = new Number(); n.setNum(1); ChannelFuture f =b.connect(host,port).sync(); f.channel().writeAndFlush(n); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); }finally { group.shutdownGracefully(); } }}
Server端
Server的handler就稍微多一点,为了验证ctx和channel的writeAndFlush到底有什么不同,我们决定建立四个Handler,两个out,两个In,然后交换它们的顺序来看效果。
handler
这里的handler就是接受一个Number类,然后让这个数加一再进行下一步操作。
inboundhandler
public class S_I_1 extends ChannelInboundHandlerAdapter{ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Number n = (Number)msg; System.out.println("S in 111 get num = " + n.getNum()); n.add(); ctx.fireChannelRead(n); //ctx.channel().writeAndFlush(n); }}
outboundhandler
public class S_O_1 extends ChannelOutboundHandlerAdapter { @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { Number n = (Number)msg; System.out.println("S out 111 get num = " + n.getNum()); n.add(); ctx.writeAndFlush(n); }}
服务器构建
public class Server { public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(),workerGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG,1024) .childOption(ChannelOption.SO_KEEPALIVE,true) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //这个object转换的如果不放在前面会在发送的时候找不到out ch.pipeline().addLast(new ObjectEncoder()); ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度 ch.pipeline().addLast(new S_I_1()); ch.pipeline().addLast(new S_O_1()); ch.pipeline().addLast(new S_I_2()); ch.pipeline().addLast(new S_O_2()); } }); try { ChannelFuture f = b.bind(10010).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }}
实验
先说实验结论就是ctx的writeAndFlush是从当前handler直接发出这个消息,而channel的writeAndFlush是从整个pipline最后一个outhandler发出。怎么样,是不是很抽象,下面画图来看一看:
啊,首先解释一下这个图,黑色的是inhandler,红色的是outhandler,前面圆形的是编解码器,必须放在pipline的最前头,否则会让信息发不出去。然后,连接建立之后,in接收到一个数1,选择ctx的writeAndFlush,那么这个数,就会直接从圆形的out出去,因为我们的结论说了,就是从当前的handler直接发出去这个消息。如果使用ctx.channel().writeAndFlush()呢,就会让这个数从红色的2开始发送,经过红色1,再发出去。
让我们看一看另一种情况:
这种情况下,我们让黑色1接收到信息之后fire到黑色2,然后让黑色2把信息writeAndFlush出去,如果使用ctx.writeAndFlush(),那么这个信息就会经过红色1而不经过红色2,如果使用ctx.channel().writeAndFlush()就会从pipline的尾部,也就是红色2开始,经过红色1发出去。
下午写代码的时候突然想到了这种情况,就是在红色的2里,如果用channel的writeAndFlush会有什么样的结果。实验之后发现,是一个死循环,2通过channel的writeAndFlush把消息送回pipline尾部,然后自己获得这个消息,再送回尾部,这样永远都发不出了,这一定要注意哦
好的,就是这样了。
这里是资源(为啥不让免费了)
- Netty中ctx.writeAndFlush与ctx.channel().writeAndFlush的区别
- Netty之writeAndFlush()流程
- ${ctx}与${pageContext.request.contextPath}的区别
- Netty : writeAndFlush的线程安全及并发问题
- ${ctx}在js中应用的问题
- ${ctx} 的那些事
- ${ctx}与${pageContext.request.contextPath}
- ${ctx}与${pageContext.request.contextPath}
- ${ctx}与${pageContext.request.contextPath}
- CTX学长的01串
- CTX学长的快速幂
- ctx赋值
- 关于${ctx}拿不到值的问题
- web.py的ctx(context)
- CTX学长的找位置游戏
- NYOJ I : CTX学长的快速幂
- NYOJ B : CTX学长的01串
- jsp之${CTX}理解
- HTML新特性-网页排版
- HTTP和HTTPS回顾
- C语言进阶-4讲: 外部全局变量和静态全局变量
- 学生数据库建立的开始阶段
- xsl随手记
- Netty中ctx.writeAndFlush与ctx.channel().writeAndFlush的区别
- React 实现井字棋游戏 (tic-tac-toe) 教程 (3) <译自官方文档>
- matlab中exist函数说明
- 前端基础(4):html语法(3): <input> 标签
- 双目相机标定之OpenCV获取左右相机图像+MATLAB单目标定+双目标定
- Codeforces887C-Solution for Cube
- jquery validate 手机号码、电话号码验证
- 已知二叉树的中序遍历和前序遍历,如何求后序遍历
- Spring Boot学习之旅:(十二)模版引擎-Thymeleaf