文章目录
- 1、TCP粘包问题
- 1.1、客户端粘包现象
- 1.2、服务端粘包
- 1.3、粘包、缺包解决
- 2、包头设计
1、TCP粘包问题
1.1、客户端粘包现象
因为客户端有一个优化算法(Nagle),
send(“abc”);
send(“123”);
send(“def”);
如果这三次发送非常紧密时间非常短,会被优化算法优化成一个数据包发送出去,这属于客户端粘包,可以关闭Nagle算法,那么调用几次send就会发送几次包
1.2、服务端粘包
不管是否解决,客户端粘包问题,服务端都会出现粘包问题,服务端两次read之间的间隔是100毫秒,那可能在这一百毫秒之间,客户端收到了三个数据包,保存到服务端的收缓存区中【abc123def】,下次read的时候就可能会出现收到全部数据
缺包
send()出去数据非常大的时候达到了8000字节的时候,就会被拆包,拆成6个包发出去,由于网络延时和阻塞,可能会出现,丢失包的情况
1.3、粘包、缺包解决
解决方式:给收发统一一个格式
包结构:包头+包体
其中包头是固定长度【10字节】,在包头中,有一个成员变量记录整个包的长度。
收包总结:
1、先收固定长度包头,10个字节
2、收满包头后,包头中有总包长度,然后算出包体长度
3、收包体长度数据。
解决粘包问题
2、包头设计
包头就是一个结构体:
1、 限制:包头最大长度,不能操作(30000字节),防止收到伪造数据包
2、包结构体
3、设置字节对齐#pragma pack(1) 设置为1字节对齐,#pragma pack()恢复原来的对齐方式
4、收包状态定义
5、每个socket对应,连接池里面的一块内存,结构体中包含四个变量处理收包,
当前状态
用于保存收到包头数据的信息数组
接收数据的头指针(指向保存包数组,可能因为某种原因包头只收到3个字节,后面的没收到,下一次收的时候从哪里放,就用他来确定)
要收多少数据(还确实多少数据,比如前面只收到了3个字节,还确实5个字节)
6、消息头+包头+包体
//包头结构
#pragma pack(1)
typedef struct _COMM_PKG_HEADER
{
unsigned short pkgLen; //报文总长度【包头+包体】--2字节,2字节可以表示的最大数字为6万多,
//包头中记录着整个包【包头—+包体】的长度
unsigned short msgCode; //消息类型代码--2字节,用于区别每个不同的命令【不同的消息】
int crc32; //CRC32效验--4字节,为了防止收发数据中出现收到内容和发送内容不一致的情况,引入这个字段做一个基本的校验用
}COMM_PKG_HEADER;
#pragma pack()
#define _PKG_HD_INIT 0 // 初始状态,准备收数据
#define _PKG_HD_RECVING 1 // 接收包中,包头不完整,继续接收中
#define _PKG_BD_INIT 2 // 包头刚好收,准备收包体
#define _PKG_BD_RECVING 3 // 接收包体中,包体不完整继续接收中
typedef struct _STRUC_MSG_HEADER
{
lpngx_connection_t pConn; // 记录对应的链接指针
uint64_t iCurrsequece; //收到数据包时记录对应的连接编号,将来用于比较是否连接已作废
}STRUC_MSG_HEADER;