none
C#究竟怎么判断socket接收数据完毕? RRS feed

  • 问题

  • 就是用socket.receive究竟怎么判断已经接收完数据了?是接受HTTP数据,我发现返回的数据最后都有个0加3个换行,这样可以判断吗?谢谢了
    2010年6月27日 8:35

答案

全部回复

  • 你好 在接收的时候一般会有一个用于接收的字节数组buffer 这个方法返回的字节数如果小于buffer的大小一般就表示已经接收完毕了

     


    I see you~,.NET交流群、微软中文论坛同城社区成都QQ群71840452http://hi.baidu.com/1987raymondMy Blog~~~
    2010年6月29日 2:26
    版主
  • 你这个说法不对,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 补充
    2014年3月18日 8:22
  • 你也不能根据接收的数据包末尾是否为空字符来判断是否终结。

                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();
                }
    

    结果也没用,除了末尾的包以外,其它包也会出现“末尾空字符”的现象。

    2014年3月18日 8:56
  • 真心觉得,为什么这个Receive不能再傻瓜一些,连while循环都不要了,直接把数据下载了,我只要反序列化一下就好了。用Socket,而不不用TcpClient的原因就在于可以获得源请求的Socket信息。
    2014年3月18日 9:06