本文主要是介绍Netty重点——TCP 粘包和拆包及解决方案上篇(二十四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
TCP 粘包和拆包基本介绍
- TCP 是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的 socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化方法(Nagle 算法),将多个较小的数据,合并成一个大的数据块,然后进行封包。这样做虽然提高了效率,但是接收端就难以分辨出完整的数据包了,因为面向流的通信是无消息保护边界的
- 由于TCP无消息保护边界,需要在接收端处理消息边界问题,也就是粘包、拆包问题
- 示意图 TCP 粘包、拆包图解 假设客户端分别发送了两个数据包 D1 和 D2 给服务,由于服务端一次读取到字节数是不确定的,故可能存在以下四种情况:
- 服务端分两次读取到了两个独立的数据包,分别是D1和 D2,没有粘包和拆包
- 服务端一次接受到了两个数据包,D1 和 D2 合在一起,称之为 TCP 粘包
- 服务端分两次读取到了数据包,第一次读取到了完整的 D1 包和 D2 包的部分内容,第二次读取到了D2包的剩余内容,这称之为TCP拆包
- 服务端分两次读取到了数据包,第一次读取到了 D1包的部分内容 D1_1,第二次读取到了D1包的剩余部分内容D1_2和完整的D2包,这种也是拆包。
TCP粘包和拆包现象实例
- 简介:在编写Netty程序时,如果没有做处理,就会发生粘包和拆包的问题
- 核心代码
public class MyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {private int count;@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {//使用客户端发送10条数据 hello,server 编号for(int i= 0; i< 10; ++i) {ByteBuf buffer = Unpooled.copiedBuffer("hello,server " + i, Charset.forName("utf-8"));ctx.writeAndFlush(buffer);}}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {byte[] buffer = new byte[msg.readableBytes()];msg.readBytes(buffer);String message = new String(buffer, Charset.forName("utf-8"));System.out.println("客户端接收到消息=" + message);System.out.println("客户端接收消息数量=" + (++this.count));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
public class MyServerHandler extends SimpleChannelInboundHandler<ByteBuf>{private int count;@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {//cause.printStackTrace();ctx.close();}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {byte[] buffer = new byte[msg.readableBytes()];msg.readBytes(buffer);//将buffer转成字符串String message = new String(buffer, Charset.forName("utf-8"));System.out.println("服务器接收到数据 " + message);System.out.println("服务器接收到消息量=" + (++this.count));//服务器回送数据给客户端, 回送一个随机id ,ByteBuf responseByteBuf = Unpooled.copiedBuffer(UUID.randomUUID().toString() + " ", Charset.forName("utf-8"));ctx.writeAndFlush(responseByteBuf);}
}
这篇关于Netty重点——TCP 粘包和拆包及解决方案上篇(二十四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!