2015-02-08 56 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