none
TcpClient is not reliable RRS feed

  • 问题

  • i used tcpclient receive data , but i find that tcpclient.avaliable is not reliable,sometimes the Avaliable<0,but the data is valiable in factly.

    so,when i recieve large data ,it will loss.

    private void Read(StringBuilder sb)
      {
      List<byte> bytesList = new List<byte>();
      NetworkStream ns = tcpCli.GetStream();  
      while (tcpCli.Available > 0)
      {
       
      int input = ns.ReadByte();
       
      //将byte加入List中
      bytesList.Add((byte)input);
      }


      byte[] bytes = new byte[bytesList.Count];
      bytesList.CopyTo(bytes);  
      sb.Append(textEncoder.GetString(bytes));
      }

    2011年6月1日 3:13

答案

  • 不是很清楚你们的通信协议是怎么搞的。。

     

    首先,服务端应该提供通信协议格式,例如前两位,或者前四位是长度,后面试什么标志之类的。觉得你现在根本就是在猜。

     

    可以参考一下 Google Protocol Buffers, 网络上传输数据。。通常都不是 Covert.ToString 然后再传输的。。所以你 Encoding.GB2132.Getstring 然后查找文本却找不到,那是正常的。。并不代表它不存在。

     

    PS: 如果服务端真的只发一堆 String,而没有任何控制信息。也只能够对着来收,收到就收,收不到就让服务器重发。。至于收错了,那是正常的事情。


    学习学习....
    2011年6月7日 3:53

全部回复

  • 从你的代码上面看不出哪里能够判断 Acailable < 0 的情况。。

     

    估计你的错误是由于没有正确处理 TCP 分包导致的。TCP 是基于流的协议,因此发送的数据可能会在任意的地方被截断,或者任意的数据包连在一起。 因此需要添加一堆代码来处理。

     

    否则上面的应用层会经常出莫名其妙的错误。


    学习学习....
    2011年6月1日 3:37
  • IGabriel

    谢谢你的回答。

    我是这样一个情况:


    服务端发送大量的数据,数据的大小大于接收端缓冲区的大小,因此我在接收的时候用


    TcpClient.Avaliable来判断数据是否已经接收完成,但是该属性却是不可靠的。有时候Avaliable<=0,但是实际上还有数据。

    2011年6月1日 3:44
  • 对你的情况有一些不明白的地方。。

     

    根据个人的使用经验, Avaliable 从来未出现小于 0 的情况,即使是一次过传一个 1.x G 的文件亦未曾出错。

    观察了一下你的代码,也未发现有捕捉 Available < 0 的代码存在。。

     

    所以不是很清楚。。为何你那么肯定地认为 Available 不可靠了。 是否是通过观察发送发发了 100M 的数据。但只接受到 90M,从而断定不可靠的?或者说是通过断点侦测的?

     

    其实。。感觉你的读数据方法是有问题的,这个程序成立的前提就是能够源源不断地接受到数据。。如果出现一瞬间的网络阻塞,或者发送方出现一瞬间的阻塞, while 循环就会中断。 后面的内容自然收不到了。

     


    学习学习....
    2011年6月1日 7:05
  •  

    IGabriel

    谢谢你的回答。

    为什么出现这种情况,我也感觉很奇怪,但我经过测试确实是有这种情况。

    服务端发送过来的字节是8910000个字节,但是tcpclient.ReceiveBufferSize默认的大小是8192

     NetworkStream ns = tcpCli.GetStream();  
      while (tcpCli.Available > 0)   //此时Avaliable 的值是8192
      {
       
      int input = ns.ReadByte(); //执行该句之后,如果传输的字节小于或等于ReceiveBufferSize的大小,Avaliable会减1.但是接收的字节数大于ReceiveBufferSize,所以执                                     //行该句之后ReceiveBufferSize还是8192

      bytesList.Add((byte)input);
      }

     byte[] bytes = new byte[bytesList.Count];  //在此处设置断点,当程序跳出循环后,我发现tcpCli.Available >0。所以我的推测是可能由于资源占用比较忙,缓冲区的数据正好读完,但是后续的数据没有进入缓冲区,所以在判断的Available的那个时刻,Avaliable=0,所以跳出了循环。当跳出循环之后,后续的数据又进入了缓冲区,所以Avaliable又>0。

    2011年6月1日 7:57
  • 通常网络传输数据都是先发长度,然后再发数据。 然后在 while 循环里面根据长度,截取足够的数据。要是一次过拿不够,就停在那里循环读取。 而非通过 avliable 来判断传输是否结束。

     

    建议你改一下接受程序。


    学习学习....
    2011年6月1日 8:57
  • 对,但是服务端不是我写的,所以我无法知道数据的长度
    2011年6月3日 0:55
  • 我通过NetWorkStream.Write方法往服务端写入一个数据,然后服务端就给客户端返回数据,通过NetWorkStream.ReadByte将服务端返回的数据都加入到List<byte>中,然后通过Encoding.GB2132.Getstring方法将二进制数据转换成中文,在转换后的中文信息里没有数据的长度。


    2011年6月3日 1:05
  • 不是很清楚你们的通信协议是怎么搞的。。

     

    首先,服务端应该提供通信协议格式,例如前两位,或者前四位是长度,后面试什么标志之类的。觉得你现在根本就是在猜。

     

    可以参考一下 Google Protocol Buffers, 网络上传输数据。。通常都不是 Covert.ToString 然后再传输的。。所以你 Encoding.GB2132.Getstring 然后查找文本却找不到,那是正常的。。并不代表它不存在。

     

    PS: 如果服务端真的只发一堆 String,而没有任何控制信息。也只能够对着来收,收到就收,收不到就让服务器重发。。至于收错了,那是正常的事情。


    学习学习....
    2011年6月7日 3:53