2014-05-17 62 views
2

使用阻止,流式傳輸.NET socket我正在連接到服務器。每當我讀數據的小塊,一切順利的話,數據被接收到我的緩衝區:爲什麼我的客戶端套接字沒有收到我的服務器套接字發送的內容?

using (var socket = new Socket(SocketType.Stream, ProtocolType.IP)) 
{ 
    socket.Connect(IPAddress.Parse("127.0.0.1"), 5000); 

    byte[] buffer = new byte[BufferSize]; 

    socket.Receive(buffer); 

    // Here buffer doesn't always contain all data the server sent me? 
    Console.WriteLine(Encoding.Default.GetString(buffer)); 
} 

在某些情況下,雖然,我沒有收到所有的服務器發送了我。數據似乎被切斷。這可能是什麼原因?

+0

這意味着作爲一個參考問題來關閉看起來相似的重複問題。請評論或提出改進建議,或者選擇其他答案。 – CodeCaster

回答

3

這是documented in the Receive() method,重點煤礦:

接收方法數據讀入到緩衝參數和返回的字節數成功讀取。您可以從面向連接和無連接的套接字調用接收。

當忽略返回值時,您將不知道緩衝區的哪一部分實際上包含相關數據。根據使用的協議,您可能事先或可能不知道內容的長度。一些協議提供這個長度,其他協議在完成時關閉連接,而另一些協議可以使用消息邊界。

您必須將接收到的數據保存在另一個緩衝區中,並在沒有更多數據可用或預期時返回或輸出整個消息緩衝區。這可以這樣來完成:

int BufferSize = 1024; 

using (var socket = new Socket(SocketType.Stream, ProtocolType.IP)) 
{ 
    socket.Connect(IPAddress.Parse("127.0.0.1"), 5000); 

    byte[] buffer = new byte[BufferSize]; 
    string message = ""; 

    int bytesReceived; 
    do 
    { 
     bytesReceived = socket.Receive(buffer); 
     message += Encoding.ASCII.GetString(buffer, 0, bytesReceived); 

    } while (bytesReceived > 0); 

    Console.WriteLine(message); 
} 

所接收的字節是ASCII字符(如在虛構的協議中定義),因此接收到的每個字節表示一個字符(不能轉換部分地接收多字節Unicode字符) 。字節被轉換爲字符串並附加到message變量。代碼循環直到服務器關閉連接。

當消息大小是在事先已知的,再次,這取決於所使用的協議,則可以創建一個消息緩衝器和那裏複製每個Receive()數據:

// Received using another Receive() call 
int messageSize = 1234; 
int totalBytesReceived = 0; 
byte[] messageBuffer = new byte[messageSize]; 

byte[] buffer = new byte[BufferSize]; 

int bytesReceived; 
do 
{ 
    bytesReceived = socket.Receive(buffer); 

    // Copy the receive buffer into the message buffer, appending after 
    // previously received data (totalBytesReceived). 
    Buffer.BlockCopy(buffer, 0, messageBuffer, totalBytesReceived, bytesReceived); 
    totalBytesReceived += bytesReceived; 

} while (bytesReceived > 0); 

// This assumes the connection wasn't closed prematurely. 
Console.WriteLine(Encoding.ASCII.GetString(messageBuffer)); 

這又可以放在一個可重複使用方法:

public byte[] ReceiveMessage(Socket socket, int messageSize) 
{ 
    byte[] messageBuffer = new byte[messageSize]; 

    int bytesReceived = 0; 
    int totalBytesReceived = 0; 
    do 
    { 
     byte[] buffer = new byte[BufferSize]; 

     // Receive at most the requested number of bytes, or the amount the 
     // buffer can hold, whichever is smaller. 
     int toReceive = Math.Min(messageSize - totalBytesReceived, BufferSize); 
     bytesReceived = socket.Receive(buffer, toReceive, SocketFlags.None); 

     // Copy the receive buffer into the message buffer, appending after 
     // previously received data (totalBytesReceived). 
     Buffer.BlockCopy(buffer, 0, messageBuffer, totalBytesReceived, bytesReceived); 

     totalBytesReceived += bytesReceived; 

    } while (bytesReceived > 0); 

    if (totalBytesReceived < messageSize) 
    { 
     throw new Exception("Server closed connection prematurely"); 
    } 

    return messageBuffer; 
} 

有它包裝一個插座NetworkStream,但它作爲has the same reading issues插座本身。您必須監視返回值,並在您收到所有字節之前一直呼叫Read()TcpClient that has a GetStream() method也一樣,你的回報值也是have to continue reading until you've read all data

相關問題