显示标签为“TCP”的博文。显示所有博文
显示标签为“TCP”的博文。显示所有博文

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

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

TCP window size (zz) - [Networking]

TCP window size (zz) - [Networking]

How many of you have notice that no matter you have a 100 Mb line you
only get near 2 Mbps, well that is
because the TCP window size is only of 32 kB or 64 kB on Linux (depends
on distribution) and 8 kB on M$ Windows.

The TCP window size is the amount of data that will be send on a
connection before a host stops and waits
for an acknowledgment. This is used by TCP to prevent congestion.
Ideally it should be:

Window size = Bandwidth x round trip time


@@WARNING@@
* If your window size is too small, you won't use the network to it's
full capacity
* If your window size is too big, you risk overloading the network
and creating congestion and packet loss
* On a WAN, setting the TCP window size correctly plays a big part in
getting good performance
(it can easily double performance or more)


The peak bandwidth of the link is typically expressed in Mbit/s. The
round-trip delay for a link can be measured with traceroute, and for
high-speed WAN
links is typically between 10 msec and 100 msec. For a 60 msec, 120 Mbps
path, the bandwidth*delay product would be 7200 kbit, or 900 kByte (kB).

...so here is how to change the
TCP Window size on Linux in order to achieve higher bandwidth.

#cd /proc/sys/net/core
#ls
message_burst netdev_max_backlog rmem_default wmem_default
message_cost optmem_max rmem_max wmem_max
-------
(The secret are on these files)
/proc/sys/net/core/rmem_default - default receive window
/proc/sys/net/core/rmem_max - maximum receive window
/proc/sys/net/core/wmem_default - default send window
/proc/sys/net/core/wmem_max - maximum send window
--------
# cat wmem_default wmem_max rmem_default rmem_max
65535
65535
65535
65535
#
(If you change these numbers you are changing the TCP window)

The theorical values are 65535 on all of them because asume bandwidth of
100
Mbits/s and the round trip time was 5 msec, the TCP window should be

(100x10^6) bytes/sec * (5x10^-3) sec = 65000 bytes or 65 kilobytes

or

500x10^3 bits (65 kilobytes)


But imagine right now we (the UPR) have a DS3 (45Mbit/sec) with Sprint
and the average
round trip is 115 ms (do ping to anywhere outside and you will get
higher numbers)

So the computation will be:

45 Mbit/sec * 115 ms
= 45e6 * 115e-3
= 5,175,000 bits / 8 / 1024
= 631 KBytes

That means that our ideal TCP Window is 631 KBytes.
# cat 646875 > /proc/sys/net/core/wmem_max
# cat 646875 > /proc/sys/net/core/wmem_default
# cat 646875 > /proc/sys/net/core/rmem_max
# cat 646875 > /proc/sys/net/core/rmem_default


Well, hope this works for you. Note that this is not using the Internet2
link yet. Probably will
require a much smaller TCP Window. Please let me know if you find any
difference on performance.

DISCLAIMER: These are teorical numbers and are not guaranty to work for
everyone in the same way.


For M$ Windows 9x users please refer to:
http://moat.nlanr.net/Software/TCPtune/


REFERENCES:
http://dast.nlanr.net/Articles/GettingStarted/TCP_window_size.html
http://ncne.nlanr.net/research/tcp/testrig/
A very useful presentation:
http://ncne.nlanr.net/training/techs/1998/980128/talks/welch

General Info:
http://www.ncsa.uiuc.edu/People/vwelch/net_perf/tcp_windows.html
http://www.psc.edu/networking/perf_tune.html (outdated 1999 but useful)

http://www.ncsa.uiuc.edu/People/vwelch/net_perf_tools.htm

TCP 粘包及分段研究 - [Networking]

TCP 粘包及分段研究 - [Networking]

这两天碰到一个TCP read buffer 满,而发送Zero window message 给Server, Server 在收到多次这样的message后断开该缓慢连接的问题。想到了几个问题,查证后特记录如下:

1. TCP Zero Window message 与 RST ACK:Zero Window message 通常在本地recieve buffer 满时发出,向server通知"已经不能再向我发数据了,已经处理不过来了",server收到这样的notify则会暂停向该client发数据。长此 以往,有些防火墙的规则会发RST message将这些慢连接干掉。

2. TCP MSS 与 MTU 分段:MSS叫Maxitum Segment Size ,通常的实现就是按照MTU来的,因此MSS一般来说大小为1500-20-20=1460。如果应用层数据太大,大于一个MSS,则TCP将作分段处 理。MTU基于物理层而言,ethnet的MTU为1500,PPPoe为1492,上层的message大小如果大于MTU,则将在IP层被分片。有的 TCP报文为保证顺序要求,设置了Dont fragment 位,指示IP层不要分片,如果这段网络上的MTU <>

3. 阻塞和非阻塞套接字,阻塞套接字会将所有的data拷贝到发送缓冲区后才返回,也就是如果窗口为16K,要发送32k的数据返回时,至少有16K的数据已 经到达对端,还有部分数据在本地缓冲区内。如果为非阻塞模式,发送32K数据将马上返回,返回的nbyte小于32K,需要通过循环将所有数据发完。

2007年8月17日星期五

TCP 数据包的合适大小?(MAX1460Bytes)

TCP 数据包的合适大小?1460Bytes

楼主thesea1978(一切随风)2005-11-23 11:25:10 在 VC/MFC / 网络编程 提问

使用TCP链接发送数据的时候,自定义的数据包如果过长,则会被自动分段发送。如果过短,则会被自动复合成较长的数据包再发送。特别是在数据量比较大且连续发送的时候更为明显。

不管自定义的包的长度如何,我希望我自定义的包被完整的发送过去,既不希望被分段发送,也不希望被复合发送。在此,向各位请教解决办法。

我想,定义一个合适的包长,且要发送定长的数据。是不是可以解决?比如,1460字节。

实在不行的话,就要在接收端加上特别的处理了。 问题点数:20、回复次数:10Top

1 楼lemony8734(lemony)回复于 2005-11-23 11:49:23 得分 0

TCP传输都会有这个问题~~

一般来说要在包中加入包体大小~

然后接收的时候根据这个大小来判断是否这个数据包已经接收完整~

如果使用UDP就不会碰到这样的问题~Top

2 楼lemony8734(lemony)回复于 2005-11-23 11:50:14 得分 0

还有,一般来说,一次send出去的包,控制在1024×4为最佳包体大小~~~Top

3 楼jia20003(『gloomy fish』兄弟们一个一个结婚刺激我想跳楼!)回复于 2005-11-23 11:56:49 得分 0

1024Top

4 楼flashboy(爱写程序的小绵羊)回复于 2005-11-23 14:39:40 得分 10

1.3K左右,另外把NANGLE算法关闭掉Top

5 楼lmf_1(lmf)回复于 2005-11-25 16:39:37 得分 10

以太网最大MSS为1460
考虑到目前大家常用的网络环境,最好在1400--1460之间较好Top

6 楼Delphityro(下岗工人)回复于 2005-11-25 23:21:10 得分 0

1024最好。Top

7 楼somexing(somexing)回复于 2005-11-26 11:41:07 得分 0

1400Top

8 楼vicky_jam(★天使亲蛙☆)回复于 2005-11-26 16:28:20 得分 0

<1024*2Top

9 楼orbit(走了走了)回复于 2005-11-26 16:36:40 得分 0

做好将自己的数据进行封装,也就是自定义一个简单的包协议,每次发送数据都包含一个描述数据大小的包头,接收端每次固定的接收一个包头大小的数据,然后根据包头中的数据大小读取相应的数据,然后再读取下一个包头,就可以保证数据的同步Top

10 楼winnuke(x86)回复于 2005-11-26 18:19:00 得分 0

一个tcp包最大可传输1432 byte