积极答复者
C#究竟怎么判断socket接收数据完毕?

问题
答案
-
你好 在接收的时候一般会有一个用于接收的字节数组buffer 这个方法返回的字节数如果小于buffer的大小一般就表示已经接收完毕了
I see you~,.NET交流群、微软中文论坛同城社区成都QQ群71840452http://hi.baidu.com/1987raymondMy Blog~~~- 已标记为答案 KeFang Chen 2010年7月2日 7:36
全部回复
-
你好 在接收的时候一般会有一个用于接收的字节数组buffer 这个方法返回的字节数如果小于buffer的大小一般就表示已经接收完毕了
I see you~,.NET交流群、微软中文论坛同城社区成都QQ群71840452http://hi.baidu.com/1987raymondMy Blog~~~- 已标记为答案 KeFang Chen 2010年7月2日 7:36
-
你这个说法不对,tcp在传输包的时候,貌似会协议每个包的大小。我就遇到这个问题,也试了很多,但没找到通用的解决方法。
1)我先用示例提供的那样:
int length = request.ReceiveFrom(RecieveBuffer, ref ep);
while(length>0)
{Receive }
这会出现卡死现象。哪怕接收完了,还卡在while中的Receive等待接收。
2)于是我改进为
while(socket.Available>0)
{Receive }
结果是不断接收,哪怕我发送8MB的数据包,它接收到16MB还在继续收。
3)于是我在改进,发现在Send()后面用Socket.Close()关闭连接后,可以让用第一种方法正常结束Receive。但如果我还要用原来的Socket连接呢?再重新连接?这明显不是一个好办法,因为太浪费开销了。而且代码理解起来也不舒服。网上也有不用Socket.Close(),而用Shutdown(),我没试过Shutdown,但估计是一个效果。
4)于是我用了您提到的解决方法,但我通常需要接收下来的数据包再反序列化,问题马上又来了。因为每个数据包的大小不一致,所以会导致数据没有完整接收完,反序列化就报错“数据意外结尾”。为什么会这样呢?我打印了每个数据包的大小,我的缓冲是102400;下面是每次接收到的数据包大小:
Length = 102400
Length = 102400 Sum = 102400
Length = 3472 Sum = 105872
Length = 102400 Sum = 208272。。。。。。
Length = 102400 Sum = 8195472
Length = 102400 Sum = 8297872
Length = 90736 Sum = 8388608 《= 这是正确的数据包完整大小。我觉得Close()是一个比较好的解决方法,但我的应用不想和服务器频繁连接和断开,这太浪费开销了。所以我要问:有更好的解决办法吗?
有的人说,应该发送一个结束标志,我也想过这个问题,但如果客户端本身的设计就是并发向服务器请求呢?如果服务器同时回送几个包的大小,我怎么知道到底哪个包是多大的?怎么计数结束收取?
所以,问题还是回到Receive本身,怎么知道接收完了?
- 已编辑 OpenNovo 2014年3月18日 8:27 补充
-
你也不能根据接收的数据包末尾是否为空字符来判断是否终结。
int length = request.ReceiveFrom(RecieveBuffer, ref ep); ms.Write(RecieveBuffer, 0, length); Console.WriteLine("Length = " + length); int ____tempSum = 0; while (length >0) { ____tempSum += length; Console.Write("Length = " + length + "\tSum = " + ____tempSum); if (RecieveBuffer[length - 1] == '\0') Console.Write("\t<- End is '\0'"); length = request.ReceiveFrom(RecieveBuffer, ref ep); ms.Write(RecieveBuffer, 0, length); Console.WriteLine(); }
结果也没用,除了末尾的包以外,其它包也会出现“末尾空字符”的现象。