TCP粘包、拆包

TCP粘包、拆包

熟悉tcp编程的可能都知道,无论是服务端还是客户端,当我们读取或发送数据的时候,都需要考虑TCP底层的粘包/拆包机制。

TCP是一个“流”协议,所谓流就是没有界限的遗传数据。可以想象下,如果河里的水就是数据,他们是连成一片的,没有分界线。TCP底层并不了解上层的业务数据具体的含义,它会根据TCP缓冲区的实际情况进行包的划分,也就是说,在业务上,我们一个完整的包可能会被TCP分成多个包进行发送,也可能把多个小包装封装成一个大的数据包发送出去,这就是所谓的TCP粘包、拆包问题。

分析TCP粘包、拆包问题产生的原因“

  1、应用程序write写入的字节大小大于套接口发送缓冲区的大小

  2、进行MSS大小的TCP分段

  3、以太网帧的payload大于MTU进行IP分片

 下面看一下粘包的现象:

Client端连续发送3次数据,下面看一下Server端的打印结果:

可以看到,Server端接收到的结果是连接在一起的,

这就是粘包的现象。

TCP粘包、拆包问题解决方案

粘包拆包问题的解决方案,根据业界的主流协议,有三种方案:

  1消息定长,例如每个报文的大小固定为200个字符,如果不够,空位补空格;

  2在包尾部增加特殊字符进行分割,例如加回车等;

  3讲消息分为消息头和消息体,在消息头中包含表示消息总长度的字段。然后进行业务逻辑的处理

netty提供了一些基础累:

1分隔符类DelimiterBasedFrameDecoder(自定义分隔符)

2FixedLengthFrameDecoder(定长)

下面看一下如何使用自定义分隔符进行拆包的,

在Server端,

接收到Client端传来的buf数据,然后通过 DelimiterBasedFrameDecoder 把数据解析成String类型的数据,看一下下面的相关实现:

我这边是通过“$_”这个字符串作为分隔符,下面看一下ServerHandler里面的响应代码:

因为在前面已经转换成String类型了,这边只是确保一下类型,进行了一下强转,这边向客户端发送的数据要是原先的buf数据,不然客户端没办法去解析,

同样的看一下Client端的程序,Client端的程序与Server端的程序类似:

看一下ClientHandler代码,ClientHandler端就把server端响应的代码进行了打印:

看一下运行结果,和原先没有使用分隔F的进行一下对比,看看有什么区别:

Server端接收到3条Client端发送的数据,没有发生粘包的现象。Client端也收到Server端响应的3条数据。

这是第一种处理TCP拆包粘包的处理方式,下面我们看一下第二种处理方式:

只需要把使用的类替换掉,并定义字节的长度,不过需要自己传输的字符串自己添加空格,如果不添加,或者设置的字节太短,都会出现粘包的现象。

原文地址:https://www.cnblogs.com/shmilyToHu/p/7094627.html