TCP的粘包和拆包问题及解决
前言
TCP属于传输层的协议,传输层除了有TCP协议外还有UDP协议。那么UDP是否会发生粘包或拆包的现象呢?答案是不会。UDP是基于报文发送的,从UDP的帧结构可以看出,在UDP首部采用了16bit来指示UDP数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。而TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界;另外从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段,基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。
解决TCP粘包和拆包得方法
- 发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
- 发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
- 可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
等等。
封装一个带首部信息得包
一个网络数据包包括:首部大小(size_t),操作类型(int)+数据(char*)。
假设有定义的结构体CMD_TYPE_T
是用来标识操作类型
typedef enum cmd_Type
{
Cmd_LoginRequest = 1,
Cmd_LoginResponse = 2,
} CMD_TYPE_T;
C语言
头文件tcpwrap.h
#ifndef TCPWRAP_H
#define TCPWRAP_H
#include <memory>
#include <netinet/in.h>
#include <string.h>
//指定字节对齐
#pragma pack(push,1)
typedef struct
{
size_t length;
int cmd;
}Packet;
#pragma pack(pop)
class TcpDataWrap
{
public:
TcpDataWrap();
public:
void sendPackData(int sockfd, CMD_TYPE_T cmd, char* buf, int bufLen);
size_t recvUnpackData (int sockfd ,char*& recvBuf);
};
#endif
源文件tcpwrap.cpp
#include "tcpwrap.h"
TcpDataWrap::TcpDataWrap() {}
//对数据进行封包,然后发送
void TcpDataWrap::sendPackData(int sockfd, CMD_TYPE_T cmd, char* buf, int bufLen)
{
Packet pack;
size_t headSize = sizeof(pack.length);
size_t cmdSize = sizeof(pack.cmd);
size_t totalLen = headSize + cmdSize + bufLen;
pack.length = totalLen - headSize;
pack.cmd = cmd;
char* sendBuf = new char[totalLen];
memset(sendBuf,0,totalLen);
memcpy(sendBuf, &pack.length, headSize);
memcpy(sendBuf + headSize, &pack.cmd, cmdSize);
memcpy(sendBuf + headSize + cmdSize, buf, bufLen);
send(sockfd, sendBuf, totalLen,0); //发送数据
delete[] sendBuf;
}
//收到得数据存储在recvbuf中,并返回recvBuf的大小
size_t TcpDataWrap::recvUnpackData (int sockfd ,char*& recvBuf)
{
size_t byteRead=0;
size_t headSize = 0;
while (byteRead <sizeof(size_t))
{
byteRead = recv(sockfd, &headSize, sizeof(size_t), MSG_PEEK); //查看数据长度是否满足包头的大小要求
}
recv(sockfd, &headSize, sizeof(size_t), 0);
recvBuf = new char[headSize];
char* pData = recvBuf;
size_t byteLeft = headSize;
while (byteLeft>0)
{
byteRead = recv(sockfd, pData, byteLeft, 0);
byteLeft -= byteRead;
pData += byteRead;
}
return headSize;
}
Qt版
头文件tcpwrap.h
#ifndef TCPWRAP_H
#define TCPWRAP_H
#include <memory>
#include <string.h>
#include <QTcpSocket>
//字节对齐
#pragma pack(push,1)
typedef struct
{
size_t length;
int cmd;
}Packet;
#pragma pack(pop)
class TcpDataWrap : public QObject
{
public:
TcpDataWrap();
public:
void sendPackData(QTcpSocket* sockfd, CMD_TYPE_T cmd, char* buf, size_t bufLen);
size_t recvUnpackData (QTcpSocket* sockfd, char*& buf);
};
#endif // TCPWRAP_H
#include "tcpwrap.h"
#include <QTcpSocket>
TcpDataWrap::TcpDataWrap(){}
//对数据进行封包,然后发送
void TcpDataWrap::sendPackData(QTcpSocket* sockfd, CMD_TYPE_T cmd, char* buf, size_t bufLen)
{
Packet pack;
size_t headSize = sizeof (pack.length); //头为8字节
size_t cmdSize = sizeof(pack.cmd); //操作位4字节
size_t totalLen = headSize + cmdSize + bufLen;
pack.length = totalLen - headSize;
pack.cmd = cmd;
char* sendBuf = new char[totalLen]; //要发送的缓冲区
memset(sendBuf,0,totalLen);
memcpy(sendBuf,&pack.length,headSize);
memcpy(sendBuf+headSize,&pack.cmd,cmdSize);
memcpy(sendBuf+headSize+cmdSize, buf, bufLen);
sockfd->write(sendBuf,totalLen);
delete [] sendBuf;
}
size_t TcpDataWrap::recvUnpackData (QTcpSocket* sockfd, char*& recvBuf)
{
size_t byteRead = 0;
size_t headSize = 0;
while (byteRead<sizeof (size_t))
{
byteRead=sockfd->bytesAvailable();
}
sockfd->read((char*)&headSize,sizeof (size_t));
recvBuf = new char[headSize];
char* pData = recvBuf;
size_t byteLeft = headSize;
while (byteLeft>0)
{
byteRead=sockfd->read(pData,byteLeft);
byteLeft -= byteRead;
pData += byteRead;
}
return headSize;
}
TCP的粘包和拆包问题及解决的更多相关文章
- TCP的粘包和拆包问题及解决办法(C#)
本文参考:https://blog.csdn.net/wxy941011/article/details/80428470 原因 如果客户端连续不断的向服务端发送数据包时,服务端接收的数据会出现两个数 ...
- 关于TCP的粘包和拆包
问题产生 一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这个就是TCP的拆包和封包问题. 下面可以看一张图,是客户端向服务端发送包: 1. 第一种情况 ...
- tcp的粘包和拆包示例以及使用LengthFieldFrameDecoder来解决的方法
粘包和拆包是什么? TCP协议是一种字节流协议,没有记录边界,我们在接收消息的时候,不能人为接收到的数据包就是一个整包消息 当客户端向服务器端发送多个消息数据的时候,TCP协议可能将多个消息数据合并成 ...
- Netty—TCP的粘包和拆包问题
一.前言 虽然TCP协议是可靠性传输协议,但是对于TCP长连接而言,对于消息发送仍然可能会发生粘贴的情形.主要是因为TCP是一种二进制流的传输协议,它会根据TCP缓冲对包进行划分.有可能将一个大数据包 ...
- TCP的粘包、拆包及解决方法
TCP粘包,拆包及解决方法 粘包拆包问题是处于网络比较底层的问题,在数据链路层.网络层以及传输层都有可能发生.我们日常的网络应用开发大都在传输层进行,由于UDP有消息保护边界,不会发生粘包拆包问题,因 ...
- netty 解决TCP粘包与拆包问题(一)
1.什么是TCP粘包与拆包 首先TCP是一个"流"协议,犹如河中水一样连成一片,没有严格的分界线.当我们在发送数据的时候就会出现多发送与少发送问题,也就是TCP粘包与拆包.得不到我 ...
- 【Netty】TCP粘包和拆包
一.前言 前面已经基本上讲解完了Netty的主要内容,现在来学习Netty中的一些可能存在的问题,如TCP粘包和拆包. 二.粘包和拆包 对于TCP协议而言,当底层发送消息和接受消息时,都需要考虑TCP ...
- C#网络编程学习(5)---Tcp连接中出现的粘包、拆包问题
本文参考于CSDN博客wxy941011 1.疑问 我们使用第四个博客中的项目. 修改客户端为:连接成功后循环向服务器发送从1-100的数字.看看服务器会不会正常的接收100次数据. 可是我们发现服务 ...
- 【游戏开发】网络编程之浅谈TCP粘包、拆包问题及其解决方案
引子 现如今手游开发中网络编程是必不可少的重要一环,如果使用的是TCP协议的话,那么不可避免的就会遇见TCP粘包和拆包的问题,马三觉得haifeiWu博主的 TCP 粘包问题浅析及其解决方案 这篇博客 ...
随机推荐
- js对象模型2
g
- 使用 setTimeout 来模拟一个 setInterval
setTimeout 超时调用:在多少时间 在执行: setinterval 每隔多少时间 就调用 例如: setTimeout这个的值是1000,也就是说在页面刷新后,1000毫秒之后才调用这个函数 ...
- HTML与CSS学习
HTML和CSS都是对页面前端的设计语言,两者是页面设计所必需掌握的两种语言.我自己的理解就是两种语言其中的HTML语言是一种标记语言,主要是对于页面的内容进行编写,表示.将自己想要在网页中表示的内容 ...
- 清北学堂—2020.1提高储备营—Day 3(图论初步(二))
qbxt Day 3 --2020.1.19 济南 主讲:李奥 目录一览 1.图论(kruskal算法,最短路径算法,拓扑排序) 总知识点:图论 一.kruskal算法 1.目的:求图的最小生成树 2 ...
- Bootstrap 手机屏幕自适应的响应式布局开关
head中添加 <meta name="viewport" content="width=device-width, initial-scale=1, shrink ...
- 使用pem连接服务器
后台同学甩给你一个pem文件,username@IP后如何链接服务器 准备:ssh客户端 例子xshell 文件->新建->主机(连接界面主机输入框输入IP)->点击用户身份-> ...
- sql 根据查询的记录生成序号的几种方式
row_number() order() 函数会为查询出来的每一行记录生成一个序号,依次排序且不会重复,注意使用row_number函数时必须要用over子句选择对某一列进行排序才能生成序号. ra ...
- (node:7584) UnhandledPromiseRejectionWarning: MongooseTimeoutError: Server selection timed out after 30000 ms
记录一次学习node.js犯的低级错误 这里遇到一个这样的问题 express连接mongoose时报错(node:7584) UnhandledPromiseRejectionWarning: Mo ...
- RS323串口连接仪器,接收仪器信息
SerialPort sp1 = new SerialPort(); getBloodPressur(); public void getBloodPressur() { try { string[] ...
- gulp常用插件之gulp-beautify使用
更多gulp常用插件使用请访问:gulp常用插件汇总 gulp-beautify这是一款使用js-beautify进行资产美化插件. 更多使用文档请点击访问gulp-beautify工具官网. 安装 ...