IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Tcp造成粘包的原因及解决措施 -> 正文阅读

[网络协议]Tcp造成粘包的原因及解决措施

粘包的概念:

TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

粘包可能由发送方造成,也可能由接收方造成。

只有TCP有粘包现象,UDP永远不会粘包

粘包不一定会发生

粘包的原因:

发送端原因: 由于TCP协议本身的机制(面向连接的可靠地协议-三次握手机制)客户端与服务器会维持一个连接(Channel),数据在连接不断开的情况下,可以持续不断地将多个数据包发往服务器,但是如果发送的网络数据包太小,那么他本身会启用Nagle算法(可配置是否启用)对较小的数据包进行合并(基于此,TCP的网络延迟要UDP的高些)然后再发送(超时或者包大小足够)。那么这样的话,服务器在接收到消息(数据流)的时候就无法区分哪些数据包是客户端自己分开发送的,这样产生了粘包.

接收端原因: 服务器在接收到数据后,放到缓冲区中,如果消息没有被及时从缓存区取走,下次在取数据的时候可能就会出现一次取出多个数据包的情况,造成粘包现象。

解决步骤:(文字说明)

网路阻塞:

发送放速度太快,接收方速度过慢导致 接收缓冲区满,从而导致阻塞。

解决办法:

接收方定义足够大的程序缓冲区从网络缓冲区尽可能的多读数据。说白了就是提高recv(buf)里面buf的大小。根据自己的电脑硬件进行设置。但这样会导致粘包问题,也会造成少包的问题。

解决粘包的办法:

定义一个pos,建立两个缓冲区 一个消息缓冲区msgBuf ?一个接收消息缓冲区recvBuf

每次接收完将recvBuf里面的数据拷贝到msgBuf里面,pos指向消息缓冲区的数据尾部。 然后根据当前接收到的数据的大小和消息头部的大小比较 如果大于消息头长度 则强转(DataHeader*)msgBuf , 在根据消息头读出实际消息的大小,再比较接收数据的大小是否大于消息的大小,是的话处理该消息,然后将msgBuf里面未处理的数据前移。Pos也需要重新计算。

char _szRecv[RECV_BUFF_SIZE] = { 0 };

/*防止网络阻塞的办法 定义一个缓冲区尽可能的吧缓冲区里面的数据读出来*/

int RecvData(ClientSocket* pClient)

{

int recvLen = recv(pClient->Sockfd(), _szRecv, RECV_BUFF_SIZE, 0);

if (recvLen <= 0)

{

printf("客户端<socket=%d>已退出,任务结束。\n", pClient->Sockfd());

return -1;

}

//接收到的数据拷贝到消息缓冲区

memcpy(pClient->msgBuf() + pClient->GetLastPos(), _szRecv, recvLen);

//指向消息缓冲区的尾部位置

pClient->SetLastPos(pClient->GetLastPos() + recvLen);

while (pClient->GetLastPos() >= sizeof(DataHeader))

{

//获得头部信息

DataHeader* header = (DataHeader*)pClient->msgBuf();

//消息缓冲区的长度大于消息的长度

if (pClient->GetLastPos() >= header->datalength)

{

//剩下为处理的数据长度

int nSize = pClient->GetLastPos() - header->datalength;

OnNetMsg(header,pClient->Sockfd());

//消息缓冲区未处理的数据前移

memcpy(pClient->msgBuf(), pClient->msgBuf() + header->datalength, nSize);

pClient->SetLastPos(nSize);

}

else//少包的情况

{

//消息缓冲区里面的数据不足一个包的时候退出去继续拷贝

break;

}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 12:07:35  更:2022-02-26 12:08:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年10日历 -2024/10/5 13:25:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码