网络通信之粘包和拆包
在解释粘包与拆包的概念前,先大致解释下网络传输过程的缓冲模型,示意图如下:
对照上图,发送端的缓冲区A是开发者在堆或栈上分配的缓冲区,并将该缓冲区的首地址作为send函数的入参,发送缓冲区B则是通信框架内部已经分配好的一段缓冲区,其大小可通过socket来设置。用户通过send发送的数据或先存储到发送缓冲区B来存储,通信框架根据实际的网络状况来决定每次发送多少字节到网络传输通道中。同样的,网络传输通道到达接收端的数据,会先存储到接收缓冲区B(通信框架维护),开发者通过recv函数从接收缓冲区B中取一定长度的数据放到自己分配的接收缓冲区A中,然后就可以对齐进行解析及处理。
当发送端连续快速的发送数据,即发送速率快于接收方的接收和处理速度,导致接收缓冲区B被塞满了,这时,发送端就不能继续发送了,网络发生阻塞。针对这一状况,一种处理方式就是需要尽快的将接收缓冲区B清空,换句话说,就是recv每次从接收缓冲区B中取的数据多一些,这样就可以避免接收缓冲区B被塞满,进而导致网络阻塞。
recv每次取的数据过多的时候,而程序每次需要处理的数据长度可能没那么长,这时候就产生了粘包,要处理粘包数据,就需要先将粘包数据拆解成程序可以处理的长度的数据,这就叫拆包,通过粘包与拆包的过程,就可以有效缓解接收端网络阻塞的问题。
验证
1. 修改客户端连续发送命令
客户端每次发送68个字节的数据,服务端接收到消息后会返回8个字节的数据
int main()
{
EasyClient client;
client.InitSocket();
client.Connect("127.0.0.1", 10087);
// 创建发送命令线程
//std::thread t(HandleSendProc, &client);
//t.detach();
// 循环接收消息并处理消息
LoginIn data;