| |
|
开发:
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地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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年11日历 | -2024/11/26 8:55:46- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |