1 TCP 粘包和拆包基本介绍

1) TCP 是面向连接的, 面向流的, 提供高可靠性服务。 收发两端(客户端和服务器端) 都要有一一成对的 socket,因此, 发送端为了将多个发给接收端的包, 更有效的发给对方, 使用了优化方法(Nagle 算法) , 将多次间隔较小且数据量小的数据, 合并成一个大的数据块, 然后进行封包。 这样做虽然提高了效率, 但是接收端就难于分辨出完整的数据包了, 因为面向流的通信是无消息保护边界的。
2) 由于 TCP 无消息保护边界, 需要在接收端处理消息边界问题, 也就是我们所说的粘包、 拆包问题, 看一张图
3) 示意图 TCP 粘包、 拆包图解
Netty  TCP 粘包和拆包 及解决方案

 对图的说明:

 假设客户端分别发送了两个数据包 D1 D2 给服务端, 由于服务端一次读取到字节数是不确定的, 故可能存在以
下四种情况:
    1) 服务端分两次读取到了两个独立的数据包, 分别是 D1 D2, 没有粘包和拆包
    2) 服务端一次接受到了两个数据包, D1 D2 粘合在一起, 称之为 TCP 粘包
    3) 服务端分两次读取到了数据包, 第一次读取到了完整的 D1 包和 D2 包的部分内容, 第二次读取到了 D2 的剩余内容, 这称之为 TCP 拆包 

    4) 服务端分两次读取到了数据包, 第一次读取到了 D1 包的部分内容 D1_1, 第二次读取到了 D1 包的剩余部

       分内容 D1_2 和完整的 D2 包。


2 TCP 粘包和拆包现象实例 (现象)

在编写 Netty 程序时, 如果没有做处理, 就会发生粘包和拆包的问题
看一个具体的实例:
MyClientHandler

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.nio.charset.Charset;
public class MyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
private int count;
@Override
public 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);
}
}
@Override
protected 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));
} 
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
View Code

相关文章:

  • 2021-10-21
  • 2021-05-26
  • 2021-07-15
  • 2023-01-05
  • 2021-11-05
  • 2022-01-01
猜你喜欢
  • 2021-06-21
  • 2022-12-23
  • 2022-01-15
  • 2021-10-02
  • 2021-09-04
  • 2021-12-05
  • 2019-10-10
相关资源
相似解决方案