TCP粘包和拆包是什么?怎么解决?

分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击人工智能教程https://www.captainai.net/troubleshooter

粘包指发送方在多次发送数据的过程中,数据包在同一个数据流中传输给了接收端,导致接收端无法正确分割数据包。例如,客户端连续发送两个数据包 “ABC” 和 “DEF”,服务端可能一次性收到 “ABCDEF”,这就像是两个包粘在了一起。产生原因主要有以下两点:

  • 发送方原因:发送方每次写入数据小于套接字(Socket)缓冲区大小,TCP 会将多次写入缓冲区的数据一次发送出去。例如,发送方先写入 “ABC”,此时缓冲区未满,接着又写入 “DEF”,然后 TCP 将 “ABCDEF” 一起发送到接收端。

  • 接收方原因:接收方读取套接字(Socket)缓冲区数据不够及时。当接收方的应用层没有及时读取接收缓冲区中的数据,新的数据又不断到来,就可能导致多个数据包被缓存,接收方一次读取时就会得到多个粘在一起的包。

半包指发送方发送的数据大于发送缓冲区,接收端一次接收的数据不是完整的数据。比如,客户端发送一个较大的数据包 “ABCDEFG”,由于数据包大小超过了 TCP 缓存容量,它会被分成多个包发送,服务端第一次可能只收到 “ABC”,这就是半包现象。半包产生的原因主要有以下方面:

  • 发送方原因:发送方每次写入数据大于套接字(Socket)缓冲区大小,数据包不得不被分割成多个小包进行发送。

一般有三种方式分包的方式:

  • 固定长度的消息;

  • 特殊字符作为边界;

  • 自定义消息结构。

固定长度的消息

这种是最简单方法,即每个用户消息都是固定长度的,比如规定一个消息的长度是 64 个字节,当接收方接满 64 个字节,就认为这个内容是一个完整且有效的消息。

但是这种方式灵活性不高,实际中很少用。

特殊字符作为边界

我们可以在两个用户消息之间插入一个特殊的字符串,这样接收方在接收数据时,读到了这个特殊字符,就把认为已经读完一个完整的消息。

HTTP 是一个非常好的例子。

null

HTTP 通过设置回车符、换行符作为 HTTP 报文协议的边界。

有一点要注意,这个作为边界点的特殊字符,如果刚好消息内容里有这个特殊字符,我们要对这个字符转义,避免被接收方当作消息的边界点而解析到无效的数据。

自定义消息结构

我们可以自定义一个消息结构,由包头和数据组成,其中包头包是固定大小的,而且包头里有一个字段来说明紧随其后的数据有多大。

比如这个消息结构体,首先 4 个字节大小的变量来表示数据长度,真正的数据则在后面。

struct {
    u_int32_t message_length;
    char message_data[];
} message;

当接收方接收到包头的大小(比如 4 个字节)后,就解析包头的内容,于是就可以知道数据的长度,然后接下来就继续读取数据,直到读满数据的长度,就可以组装成一个完整到用户消息来处理了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值