Java NIO框架Netty教程(四)- ChannelBuffer

字符串消息收发中提到。ChannelBufferNetty中非常重要的概念。所有消息的收发都依赖于这个Buffer。我们通过Netty的官方的文档来了解一下,基于流的消息传递机制。

In a stream-based transport such as TCP/IP, received data is stored into a socket receive buffer.

Unfortunately, the buffer of a stream-based transport is not a queue of packets but a queue of bytes. It

means, even if you sent two messages as two independent packets, an operating system will not treat them

as two messages but as just a bunch of bytes. Therefore, there is no guarantee that what you read is exactly

what your remote peer wrote. For example, let us assume that the TCP/IP stack of an operating system has

received three packets:

+-----+-----+-----+

| ABC | DEF | GHI |

+-----+-----+-----+

Because of this general property of a stream-based protocol, there' high chance of reading them in the

following fragmented form in your application:

+----+-------+---+---+

| AB | CDEFG | H | I |

+----+-------+---+---+

Therefore, a receiving part, regardless it is server-side or client-side, should defrag the received data into one

or more meaningful frames that could be easily understood by the application logic. In case of the example

above, the received data should be framed like the following:

+-----+-----+-----+

| ABC | DEF | GHI |

+-----+-----+-----+

</div>

您理解了没,简单翻译一下就是说。在TCP/IP这种基于流传递的协议中。他识别的不是你每一次发送来的消息,不是分包的。而是,只认识一个整体的流,即使分三次分别发送三段话:ABCDEFGHI。在传递的过程中,他就是一个具有整体长度的流。在读流的过程中,如果我一次读取的长度选择的不是三个,我可以收到类似ABCDEFGHI这样的信息。这显然是我们不想看到的。所以说,在你写的消息收发的系统里,需要预先定义好这种解析机制,规定每帧(次)读取的长度。通过代码来理解一下:

全文详见个人独立博客:https://www.coderli.com/netty-channel-stream/

Java NIO框架Netty教程(四)- ChannelBuffer在字符串消息收发中提到。ChannelBuffer是Netty中非常重要的概念。所有消息的收发都依赖于这个Buffer。我们通过Netty的官方的文档来了解一下,基于流的消息传递机制。 In a stream-based transport such as TCP/IP, received data is stored into a socket receive buffer. Unfortunately, the buffer of a stream-based transport is not a queue of packets but a queue of bytes. It means, even if you sent two messages as two independent packets, an operating system will not treat them as two messages but as just a bunch of bytes. Therefore, there is no guarantee that what you read is exactly what your remote peer wrote. For example, let us assume that the TCP/IP stack of an operating system has received three packets: +-----+-----+-----+ | ABC | DEF | GHI | +-----+-----+-----+ Because of this general property of a stream-based protocol, there' high chance of reading them in the following fragmented form in your application: +----+-------+---+---+ | AB | CDEFG | H | I | +----+-------+---+---+ Therefore, a receiving part, regardless it is server-side or client-side, should defrag the received data into one or more meaningful frames that could be easily understood by the application logic. In case of the example above, the received data should be framed like the following: +-----+-----+-----+ | ABC | DEF | GHI | +-----+-----+-----+ </div> 您理解了没,简单翻译一下就是说。在TCP/IP这种基于流传递的协议中。他识别的不是你每一次发送来的消息,不是分包的。而是,只认识一个整体的流,即使分三次分别发送三段话:ABC、DEF、GHI。在传递的过程中,他就是一个具有整体长度的流。在读流的过程中,如果我一次读取的长度选择的不是三个,我可以收到类似AB、CDEFG、H、I这样的信息。这显然是我们不想看到的。所以说,在你写的消息收发的系统里,需要预先定义好这种解析机制,规定每帧(次)读取的长度。通过代码来理解一下: /** * @author lihzh * @alia OneCoder * @blog http://www.coderli.com */ public class ServerBufferHandler extends SimpleChannelHandler { /** * 用户接受客户端发来的消息,在有客户端消息到达时触发 * * @author lihzh * @alia OneCoder */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { ChannelBuffer buffer = (ChannelBuffer) e.getMessage(); // 五位读取 while (buffer.readableBytes() >= 5) { ChannelBuffer tempBuffer = buffer.readBytes(5); System.out.println(tempBuffer.toString(Charset.defaultCharset())); } // 读取剩下的信息 System.out.println(buffer.toString(Charset.defaultCharset())); } } /** * @author lihzh * @alia OneCoder * @blog http://www.coderli.com */ public class ClientBufferHandler extends SimpleChannelHandler { /** * 当绑定到服务端的时候触发,给服务端发消息。 * * @alia OneCoder * @author lihzh */ @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { // 分段发送信息 sendMessageByFrame(e); } /** * 将<b>"Hello, I'm client."</b>分成三份发送。 <br> * Hello, <br> * I'm<br> * client.<br> * * @param e * Netty事件 * @author lihzh */ private void sendMessageByFrame(ChannelStateEvent e) { String msgOne = "Hello, "; String msgTwo = "I'm "; String msgThree = "client."; e.getChannel().write(tranStr2Buffer(msgOne)); e.getChannel().write(tranStr2Buffer(msgTwo)); e.getChannel().write(tranStr2Buffer(msgThree)); } /** * 将字符串转换成{@link ChannelBuffer},私有方法不进行字符串的非空判断。 * * @param str * 待转换字符串,要求非null * @return 转换后的ChannelBuffer * @author lihzh */ private ChannelBuffer tranStr2Buffer(String str) { ChannelBuffer buffer = ChannelBuffers.buffer(str.length()); buffer.writeBytes(str.getBytes()); return buffer; } } 服务端输出结果: Hello , I'm clie nt. 这里其实,服务端是否分段发送并不会影响输出结果,也就是说,你一次性的把”Hi, I’m client.”这段信息发送过来,输出的结果也是一样的。这就是开头说的,传输的是流,不分包。而只在于你如何分段读写。icon-default.png?t=N7T8https://www.coderli.com/netty-channel-stream/交流探讨,加入群聊【Java学习交流(982860385)】

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值