2007年10月27日星期六

TCP粘包的问题大家是怎么处理的

TCP粘包的问题大家是怎么处理的

楼主karllere(我想换工作,哪有招C++游戏程序员的联系我。)2005-06-13 08:32:36 在 VC/MFC / 网络编程 提问

如果网速过慢,客户端两次发送的数据可能会被服务端一次就全部接收。
那么这种情况下要如何分清服务端接收到的数据包是客户端几次发送的呢!
有一种方法是给每次发送的数据包加上数据包的长度,可是这仲做法如果网上出现丢包怎么办呀! 问题点数:0、回复次数:19Top

1 楼fisker0303(天塌了,地陷了,小花狗不见了.)回复于 2005-06-13 09:43:01 得分 0

http://www.xiaozhou.net/ReadNews.asp?NewsID=240Top

2 楼fisker0303(天塌了,地陷了,小花狗不见了.)回复于 2005-06-13 09:43:34 得分 0

一般来说,TCP的可靠性是应该充分相信的。Top

3 楼karllere(我想换工作,哪有招C++游戏程序员的联系我。)回复于 2005-06-13 10:39:02 得分 0

我想用下面的方法实现分包

每一个数据包在发送时定义如下格式
数据包长度|数据包序号|数据包内容

可是上面的形式在一定的情况下是错误的
就是如果在客户端一份数据被自动分成两个数据包发送,而且第二个数据包在途中丢失,那么数据就不能完整的到达服务端了。

大家谁有TCP报头的数据格式资料啊!Top

4 楼helldream2002()回复于 2005-06-13 10:51:09 得分 0

只要协议定义得好,粘包就好解决
一般来说协议中都应该包含包头和数据长度Top

5 楼younggle(洋溢)回复于 2005-06-13 10:57:44 得分 0

自己定义一个协议头,协议头的长度是固定的,协议头包含数据内容的长度。
接收消息时,先接收固定长度的协议头,然后根据协议头中数据的长度再接收数据内容。
也就是说,一条消息分2次接收。
这样可以处理粘包问题的。Top

6 楼alfwolf(木马煞)回复于 2005-06-13 10:58:18 得分 0

是的,这样的情况你必须定义你的数据包的格式,包头-信息类别-长度等,必要时需要加校验位和结束字符.
但是TCP报文是可靠的.Top

7 楼qrlvls( 空 气 )回复于 2005-06-13 11:11:01 得分 0

通过自定义帧格式来完成,在帧中加入长度字段Top

8 楼qrlvls( 空 气 )回复于 2005-06-13 11:11:27 得分 0

同意 karllere ,不过序号不需要,因为 TCP 不会乱序Top

9 楼karllere(我想换工作,哪有招C++游戏程序员的联系我。)回复于 2005-06-13 14:15:44 得分 0

请看下面的这两组数据

报头 | 报文
10 ABCDEFGHIJ
8 ABCDEFGH

假设以上报文的第一组被操作系统分成两次发送
第一次为 10ABCD
第二次为 EFGHIJ
如果第二次的数据丢失,下一组数据8ABCDEFGH又到达了。
那么在缓冲区中就会有这样的形式10ABCD8ABCDEFGH
根据数据格式定义,在一次读取数据时就会取出10ABCD8ABCDE
如果出现以上情况的话就会造成所有后续发来的数据包全部读取错误。
Top

10 楼karllere(我想换工作,哪有招C++游戏程序员的联系我。)回复于 2005-06-13 19:23:05 得分 0

MFC中的CSocket类内部会自动处理粘包和丢包的问题吗?Top

11 楼cryptonym(想裸睡)回复于 2005-06-13 22:13:41 得分 0

tcp的协议层给你处理了丢包,所以你都不需要考虑丢包的问题。

你把收到的数据放倒一个buffer里,从里面找header,然后解析出数据就ok了。

如果udp的话会乱序,tcp都不需要考虑这些的。Top

12 楼AntonlioX(做人要厚道)回复于 2005-06-13 22:39:08 得分 0

可以使用如下的方法接收数据:

需要循环调用Receive的 知道你实际接收的字节数== 你本来打算接收的字节数

下面是我的程序中的一段代码

BOOL MyReceiveData(CSocket *psocket,char *data,DWORD len)
{
DWORD left,idx,ret;
left=len;
idx=0;

while(left>0)
{
ret = psocket->Receive(&data[idx],left,0 );
if( ret == SOCKET_ERROR)
{
return FALSE;
}
left-=ret;
idx+=ret;
}

return (idx==len)?TRUE:FALSE;
}Top

13 楼hxzb7215191(天行健,君子以自强不息)回复于 2005-06-13 23:10:25 得分 0

老问题,这东西还是使用自己定义的协议。

说明你的数据包的大小。

使用那个socket的控件就爽多了。

Top

14 楼karllere(我想换工作,哪有招C++游戏程序员的联系我。)回复于 2005-06-14 10:52:13 得分 0

CSocketFile 是完成什么优化工作的呢!
在MFC的示例中总是说要将CSocket、CSocketFile和CArchive联合使用来完成信息的收发工作。
可是我感觉这样还不如真接用CAsyncSocket::Receive方便呢!
我就在想...
CSocketFile是不是内部有处理粘包的机制啊!

还有就是对于Socket的一切猜想都需要一个测试工具来验证,那么谁有好的测试工具呢!
能不能给我提供一个呀!Top

15 楼wilddragon(东瀛倭族自治州州长)回复于 2005-06-14 17:36:38 得分 0

MFC的CSocketFile有毛病的,千万别用。在粘包时经常出问题,最后我放弃用它,就好了。
用CAsyncSocket::Receive接收下来以后,自己处理吧。Top

16 楼qianyong325(帝王企鹅)回复于 2005-06-14 17:55:04 得分 0

发送数据的协议定好,一般有 包头,长度,数据段,校验(有的还有包尾),然后写个协议控制层专门处理分包,粘包的问题

没有评论: