如何解决网络传送的粘包问题

cwj2009 2010-09-08 09:46:26
请问各位你们是如何解决粘包问题的?
有人说在包头附带包大小。但是我不清楚如何设置,因为涉及到包大小是int类型然后又要转换成char类型,然后又要跟包内容进行结合形成“包头+包内容”的形式转发出去。
比如我在发送端发送“helloworld”包内容,共10个字节,我就设置包头为10,那么整个包就是"10helloworld"。
我在接收端接收到的包要怎么判断这个包大小是10而不是1呢?

我不想设置标识位,有人建议包头固定为2个字节,就是int类型的2个字节,这样可以程序固定读取头2个字节作为包头。2个字节的包头要转换成char类型再传送出去我这里有点不懂。比如说我要传送长度为256的字符串,就是int 256用itoa转成字符串那就是"256"可是占用了3个字节啊,如果我固定读取2个字节,那可是只能读到25啊!?

求助啊!
...全文
289 21 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
lijianli9 2010-09-12
  • 打赏
  • 举报
回复
每次先读取包头长度的数据,然后根据包头中自己封装的特征去获取另外长度的数据。
MYNAMELIULI 2010-09-12
  • 打赏
  • 举报
回复
每次先读取包头长度的数据,然后根据包头中自己封装的特征去获取另外长度的数据。
ringerxyz 2010-09-11
  • 打赏
  • 举报
回复
TCP 协议里本身就不需要理会包的概念,包是像IP/UDP这类协议里才有的概念

TCP里的数据是stream(流),建议楼主可以看看《unix 网络编程》,对在windows下的开发一样有用
cwj2009 2010-09-09
  • 打赏
  • 举报
回复
真论坛咋回事,没人顶了
cwj2009 2010-09-09
  • 打赏
  • 举报
回复
16楼的程序很好。我有空使用一下,结贴给你分数
Joininthefun 2010-09-09
  • 打赏
  • 举报
回复
你把收到的数据按照顺序放到你的接收缓冲区中,你的处理线程从缓冲区中取数据,每次按照你制定包的协议是一个完整的包就可以了,
wujiabao 2010-09-09
  • 打赏
  • 举报
回复


typedef struct _data_packet {
int packetlen;
char databuf[1];
}data_packet, *pdata_packet;

//server
strcpy(message,"X=1366");
length=strlen(message) + sizeof(data_packet);
pdata_packet sdata = (pdata_packet)malloc(length);
sdata->packetlen = length;
strcpy(sdata->packetlen, message);
if (send(*m_socket,sdata,length,0)==SOCKET_ERROR )
{
AfxMessageBox("无法发送屏幕分辨率数据");
return 0;
}


//client
pdata_packet rdata;
int ret,packetlen, readlen = 0;
ret = recv(m_socket,&packetlen,4,0);
if(ret != SOCKET_ERROR) {
rdata = (pdata_packet)malloc(packetlen);
rdata->packetlen = packetlen;
readlen += ret;
while(readlen <= packetlen) {
ret = recv(m_socket, (char *)rdata + readlen, packlen - readlen, 0);
if(ret != SOCKET_ERROR)readlen += ret;
else {
AfxMessageBox("接收错误");
closesocket(m_socket);
return false;
}
}
}

cwj2009 2010-09-09
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 mayudong1 的回复:]
你为什么非要执着于包长度要用字符串来表示呢?
[/Quote]
因为我不懂如何用其他方式表示啊
这不是鸭头 2010-09-09
  • 打赏
  • 举报
回复

typedef struct DataPacket
{
char szHead[2];
USHORT usID;
char cCmdType;
USHORT usLength;
char szData[MAX_DATA_LENG];
char szCRC[2];
char szTail[2];
DataPacket()
{
*szHead = 0x00;
*(szHead +1) = 0x00;
usID = 0;
cCmdType = 0x00;
memset(szData,0,MAX_DATA_LENG);
*szCRC = 0x00;
*(szCRC + 1) = 0x00;
*szTail = 0x00;
*(szTail + 1) = 0x00;
}
}DATAPACKET ,*PDATAPACKET;

不能直接发送这个结构体,要封包处理
wgm001 2010-09-09
  • 打赏
  • 举报
回复
“包长度#包内容”的这段代码不就是了吗? 多注意些就可以了, 如recv和send什么的....
这不是鸭头 2010-09-09
  • 打赏
  • 举报
回复
typedef struct DataPacket
{
char szHead[2];
USHORT usID;
char cCmdType;
USHORT usLength;
char szData[MAX_DATA_LENG];
char szCRC[2];
char szTail[2];
DataPacket()
{
*szHead = 0x00;
*(szHead +1) = 0x00;
usID = 0;
cCmdType = 0x00;
memset(szData,0,MAX_DATA_LENG);
*szCRC = 0x00;
*(szCRC + 1) = 0x00;
*szTail = 0x00;
*(szTail + 1) = 0x00;
}
}DATAPACKET ,*PDATAPACKET;

发送的时候自己封包,接收的时候自己解包。
mayudong1 2010-09-09
  • 打赏
  • 举报
回复
你为什么非要执着于包长度要用字符串来表示呢?
cwj2009 2010-09-08
  • 打赏
  • 举报
回复
我自己编写了一段解决的办法。包格式为“包长度#包内容”其中“包长度#”为字符格式,总共5个字节,包长度使用itoa()获取,因为最大为1500所以最多为4个字符,第五个字符为#,如果包长不足4个字符则末尾加#补位。这个包头就是固定5个字符了。接收的时候固定读取5个字符,使用atoi即可后去包长度。
这个是发送端代码:

int length;
char head[6];
char message[1001];
char str[1006];
strcpy(message,"X=1366");
length=strlen(message);
itoa(length,head,10);
for (int i=strlen(head);i<5;i++)
{
head[i]='#';
}
head[5]='\0';
strcpy(str,head);
strcat(str,message);
str[length+5]='\0';
if (send(*m_socket,str,length+5,0)==SOCKET_ERROR )
{
AfxMessageBox("无法发送屏幕分辨率数据");
return 0;
}

strcpy(message,"Y=766");
length=strlen(message);
itoa(length,head,10);
for (int i=strlen(head);i<5;i++)
{
head[i]='#';
}
head[5]='\0';
strcpy(str,head);
strcat(str,message);
str[length+5]='\0';
if (send(*m_socket,str,length+5,0)==SOCKET_ERROR )
{
AfxMessageBox("无法发送屏幕分辨率数据");
return 0;
}

以下是接收端代码:

char head[6];
char text[1001];
int length;
if (recv(m_socket,head,5,0)==SOCKET_ERROR)
{
AfxMessageBox("接收错误");
return false;
}
head[5]='\0';
length=atoi(head);

if (recv(m_socket,text,length,0)==SOCKET_ERROR)
{
AfxMessageBox("接收错误");
return false;
}
text[length]='\0';
AfxMessageBox(text);
if (recv(m_socket,head,5,0)==SOCKET_ERROR)
{
AfxMessageBox("接收错误");
return false;
}
head[5]='\0';
length=atoi(head);

if (recv(m_socket,text,length,0)==SOCKET_ERROR)
{
AfxMessageBox("接收错误");
return false;
}
text[length]='\0';
AfxMessageBox(text);



程序代码有点杂差,请各位高手优化
cwj2009 2010-09-08
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 kemee 的回复:]
这个要mark学习

P.S vckbase里是说那篇说确实能解决的文章吧。。也米说怎么解决,人家好像得出结论说粘包存在,也可以解决就没了
[/Quote]

对啊。我也看过了这篇文章,好像具体如何解决没有详细说,只提供了几个思路,其中几个还不是很理想的
kemee 2010-09-08
  • 打赏
  • 举报
回复
这个要mark学习

P.S vckbase里是说那篇说确实能解决的文章吧。。也米说怎么解决,人家好像得出结论说粘包存在,也可以解决就没了
xgPaul 2010-09-08
  • 打赏
  • 举报
回复
自己制定包协议,根据包协议接收数据。可以先接收包长,再根据包长接收数据部分。。。
jasonM2008 2010-09-08
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 visualeleven 的回复:]
自己封装协议,加个包头信息,然后接收到包头信息以后,再按包头的字节大小接收后续信息
[/Quote]
即使你的包大小是不固定的,但是你的包头最好固定。这样就好办了。每次都收到至少包头大小的包再来决定还需要收多少字节。。还有,你可以参考VCKBASE里面的一篇关于粘包问题的文章!
Eleven 2010-09-08
  • 打赏
  • 举报
回复
自己封装协议,加个包头信息,然后接收到包头信息以后,再按包头的字节大小接收后续信息
「已注销」 2010-09-08
  • 打赏
  • 举报
回复
你所谓“粘包”,其实是一个好的特性,使TCP可以充分利用报文,多携带一些数据。
用流协议,必须自己组包,这是基本常识。

如何组包? 当然是根据上层协议。
晓灬佩恩 2010-09-08
  • 打赏
  • 举报
回复
用比特位存储 数据包长度,这样 两个字节就可以发 2^15次方的长度,应该够去了

其实TCP 一个数据包最多只能发1500字节,这是协议规定了的
加载更多回复(1)

18,363

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧