2015-02-08 103 views
0

我试图发送一个非常大的信息到服务器,(大小11000),并有问题。信息未达到完整。Winsock接收数据

看代码:

在我的服务器上有一个循环。

do 
    { 

     Tick = Environment.TickCount; 

     Listen.AcceptClient(); 
     Listen.Update(); 
    } 

Listen.update

public static void UpdateClient(UserConnection client) 
    { 
     string data = null; 
     Decoder utf8Decoder = Encoding.UTF8.GetDecoder(); 
     // byte[] buffer = new byte[client.TCPClient.Available]; 
      //try 
      //{ 
       //client.TCPClient.GetStream(). 
      // client.TCPClient.GetStream().Read(buffer, 0, buffer.Length); 
      //} 
      //catch 
      //{ 
      // int code = System.Runtime.InteropServices.Marshal.GetExceptionCode(); 
      // Console.WriteLine("Erro Num: " + code); 
      //} 
      //data = Encoding.UTF8.GetString(buffer); 
      //Console.WriteLine("Byte is: " + ReadFully(client.TCPClient.GetStream(), 0)); 
      Console.WriteLine("Iniciando"); 
      byte[] buffer = ReadFully(client.TCPClient.GetStream(), 0); 
      int charCount = utf8Decoder.GetCharCount(buffer, 0, buffer.Length); 
      Char[] chars = new Char[charCount]; 
      int charsDecodedCount = utf8Decoder.GetChars(buffer, 0, buffer.Length, chars, 0); 

      foreach (Char c in chars) 
      { 
       data = data + String.Format("{0}", c); 
      } 

      int buffersize = buffer.Length; 
      Console.WriteLine("Byte is: " + buffer.Length); 


      Console.WriteLine("Data is: " + data); 
      Console.WriteLine("Size is: " + data.Length); 
      Server.Network.ReceiveData.SelectPacket(client.Index, data); 
    } 
    /// <summary> 
    /// Reads data from a stream until the end is reached. The 
    /// data is returned as a byte array. An IOException is 
    /// thrown if any of the underlying IO calls fail. 
    /// </summary> 
    /// <param name="stream">The stream to read data from</param> 
    /// <param name="initialLength">The initial buffer length</param> 
    public static byte[] ReadFully(Stream stream, int initialLength) 
    { 
     // If we've been passed an unhelpful initial length, just 
     // use 32K. 
     if (initialLength < 1) 
     { 
      initialLength = 32768; 
     } 

     byte[] buffer = new byte[initialLength]; 
     int read = 0; 

     int chunk; 

     chunk = stream.Read(buffer, read, buffer.Length - read); 

     checkreach: 
      read += chunk; 

      // If we've reached the end of our buffer, check to see if there's 
      // any more information 
      if (read == buffer.Length) 
      { 
       int nextByte = stream.ReadByte(); 
       // End of stream? If so, we're done 
       if (nextByte == -1) 
       { 
        return buffer; 
       } 
       // Nope. Resize the buffer, put in the byte we've just 
       // read, and continue 
       byte[] newBuffer = new byte[buffer.Length * 2]; 
       Array.Copy(buffer, newBuffer, buffer.Length); 
       newBuffer[read] = (byte)nextByte; 
       buffer = newBuffer; 
       read++; 
       goto checkreach; 
      } 

     // Buffer is now too big. Shrink it. 
     byte[] ret = new byte[read]; 
     Array.Copy(buffer, ret, read); 
     return ret; 
    } 

Listen.AcceptClient

//Tem alguém querendo entrar na putaria? ;D 
    if (listener.Pending()) 
    { 
     //Adicionamos ele na lista 
     Clients.Add(new UserConnection(listener.AcceptTcpClient(), Clients.Count())); 

,这是我的Winsock服务器。

任何人都有提示或解决方案?

回答

0

从这里开始:Winsock FAQ。它会解释你需要知道的一些事情,包括你不可能在Read()的单个调用中读取所有发送的数据。每个单独的TCP程序都需要包含某种逻辑,它将通过某种类型的循环接收数据,并且在大多数情况下还包括逻辑来解释接收到的数据,以识别接收数据的各个元素之间的边界(例如,逻辑消息等。唯一的例外是当应用协议规定从连接到闭包的整个传输代表一个“单元”,在这种情况下,唯一重要的边界是流的末尾)。

除了(解决只是一些很多事情错在代码的点点你这里包括):

  • 不要使用TcpClient.Available;在正确的代码中不需要。
  • 不要使用Marshal.GetExceptionCode()检索异常信息管理例外
  • 不要使用Convert.ToInt32()当你的价值已经是System.Int32一个实例。更一般地说,在简单演员可以完成同样的事情的情况下,不要使用Convert(即使这里不需要演员,但是我可以从这里的代码中知道你的一般习惯是什么......你应该打破这个习惯)。
  • 不要只是忽略异常。要么做些事情,要么处理他们,要么让他们向上传播调用堆栈。如果Read()方法引发异常,则UpdateClient()方法中的其余代码无法正常工作,但无论如何您都要继续执行它。
  • 不要NetworkStream对象上使用Flush()方法。它什么都没做(只是因为Stream类需要它)。
  • 使用Stream.ReadAsync(),而不是致力于一个线程每个连接
  • 通过包括异常类型和可变接受异常对象引用
  • 使用持续Decoder捕获异常对象来解码UTF8编码的文本(或任何其他可变字节长度的文本编码),以便如果字符的编码表示跨越多个接收缓冲区,文本仍然可以正确解码。

最后:


附录:

  • 不要使用goto声明。使用适当的循环(例如while)。如果您使用了正确的循环,那么您可能会避免代码中的错误,因为您无法分支回实际的Read()调用。
  • 不要期望Read()方法来填充您通过它的缓冲区。不仅如此(如上所述)不能保证所有发送的数据将在一次调用中返回到Read(),但不保证您在Read()返回之前将传递给Read()的整个缓冲区填满。
  • 不要一次读取一个字节。这是杀死性能和/或引入错误的最可靠方法之一。在你自己的例子中,我没有看到任何明显的错误–你只有(打算)在查找更多数据时读取单个字节,然后(打算)返回读入更大的缓冲区–,但它不是必需的尝试阅读更多的数据通常&hellip;这将得到相同的信息,而无需特殊情况下的代码,可导致错误,并在任何情况下使代码更难理解)。
  • 看网络代码的其他例子和教程。重新发明轮子可能最终会导致一个好的解决方案,但是这种方法的可能性很低,而且比其他人的好例子要花费更多的时间和更容易出错。

我会重申:请阅读Winsock FAQ。它有很多有价值的信息,每个想写网络代码的人都需要知道。

我也会重申:没有COMPLETE代码示例,您无法得到确切的答案。

+0

感谢您的提示,但我的问题仍然存在...问题编辑。 – user3571412 2015-02-08 22:45:07