OneCoder Avatar
OneCodercoderli.com · 958 篇博文
{ } Java

Java 服务端架构

Spring、Netty、日志框架与工程化实战

🎨 视觉封面

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

📅 2012-07-13·✍️ onecoder·计算中...·⏱️ 9 分钟
#Netty

字符串消息收发中提到。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 |
+-----+-----+-----+

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

Java 26 行
/**
 * @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()));
	}

}
Java 53 行
/**
 * @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;
	}

}

服务端输出结果:

Code 4 行
Hello
, I'm
 clie
nt.

这里其实,服务端是否分段发送并不会影响输出结果,也就是说,你一次性的把"Hi, I'm client."这段信息发送过来,输出的结果也是一样的。这就是开头说的,传输的是流,不分包。而只在于你如何分段读写。

💡 OneCoder 资源指引

所有代码开源上传至 GitHub:yummy-code 仓库 · GESP 专题站:GESP WIKI

🤝 技术交流与答疑

欢迎加入:C++ GESP/CSP 考级答疑群(688906745)Java/Python交流群(982860385),点击可直接加群。

📚

猜你想读 · 相关文章推荐

Java 架构演进与实战 · Netty⏱️ 2 分钟

开源Java高性能NIO框架推荐 - Netty

作为一个Java程序员,多方面的知识储备是相当重要的。面对各种的情况,都有自己的解决方案也是一种能力的体现。Java优秀的开源项目很多,除了传统的SSH,作为一个Java程序员,你应该知道的更多:) Netty简介 Netty 是一个异步的,事件驱动的网络编程框架和工具,使用Netty可以快速开发出可维护的,高性能、高...

阅读全文 →
Java 架构演进与实战 · Netty⏱️ 14 分钟

Netty Object传输问题解决

使用Netty开发分布式框架,对象的传输是基本的需求。但是,在开发中却总遇到服务端接受不到客户端的对象发送数据。遂动手解决。 如果看到最后,你可能会发现,笔者的问题是那么的二,不适合你。。所以,你可以决定不看,或者只看样例代码。笔者记录的是,个人的解决过程。 先看一下官方提供的,对象传输的样例代码:(核心部分) 代码很...

阅读全文 →
Java 架构演进与实战 · Netty⏱️ 7 分钟

Java NIO框架Netty教程(一) - Hello Netty

先啰嗦两句,如果你还不知道Netty是做什么的能做什么。那可以先简单的搜索了解一下。我只能说Netty是一个NIO的框架,可以用于开发分布式的Java程序。具体能做什么,各位可以尽量发挥想象。技术,是服务于人而不是局限住人的。 Netty的简介和下载可参考:开源Java高性能NIO框架推荐。注意,此时的最新版已经为3....

阅读全文 →
OneCoder

OneCoder (lihongzheshuai)

一个中年人的自留地,记录学习 C++、GESP/NOI、Java、Python 与算法架构的心得体会。本站唯一网址:coderli.com

读者讨论与留言

0 条讨论
✨ 支持点击留言直接回复 · Markdown 引用格式
💬 还没有读者留言,快来成为第一个讨论者吧!