2016-08-22 81 views
-1

因此,當服務器發送小於時16384字節然後客戶端接收所有沒有問題的數據。 但是,一旦服務器發送更多的數據,客戶端會收到奇怪的數量,比如6140.它並不總是這樣做,但它大部分時間都是這樣,但它經常這樣做。它很少收到完整的16384字節。C#套接字:客戶端在接收大緩衝區時沒有收到所有字節

起初我以爲連接花了很長時間才能發送全部數據,所以我將接收超時設置爲30秒(30000毫秒)。 這並沒有解決任何問題。每次我收到數據時,我都會使用一個新的字節數組,以便它不會被另一個BeginRecieve()覆蓋。

我能想到的唯一的事情是硬件(計算機)無法在內存中保存這些大量的字節,因此會截斷緩衝區。 我有很多的代碼,但是這是事物的基礎:

Server代碼(只是一些吧):

private void RecieveCallBack(IAsyncResult ar) 
{ 
    Socket client = (Socket)ar.AsyncState; 
    try 
    { 
     int len = client.EndReceive(ar); 
     byte[] tempBuffer = new byte[len]; 
     Array.Copy(buffer, tempBuffer, len); 
     object RequestObject = GetRequestObject(tempBuffer); // just deserializes the buffer 
     byte[] response = GetResponseFromObject(RequestObject, client); // creates a buffer to return to the client 
     client.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(SendCallBack), client); 
    } 
    catch (Exception) 
    { 
     Program.Log("Client disconnected"); 
     client.Close(); 
     clientSockets.Remove(client); 
     Program.UpdateClientCount(clientSockets.Count); 
    } 
} 

private void SendCallBack(IAsyncResult ar) 
{ 
    Socket client = (Socket)ar.AsyncState; 
    int sent = client.EndSend(ar); 
    Program.Log(sent); // log shows that server sent 16384 bytes 
    try 
    { 
     client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), client); 
    } 
    catch (Exception e) 
    { 
     Program.Log(e.Message); 
    } 
} 

客戶端代碼(只是一些吧):

static void SendRequest(object obj) 
{ 
    byte[] buffer = SerializeObject(obj); 
    try 
    { 
     serverSockect.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(SendCallBack), null); 
    } 
    catch // the send failed 
    { 
     serverSockect.Close(); 
     ConnectedToServer = false; 
    } 
} 

static Queue<byte[]> buffers = new Queue<byte[]>(); 

static private void SendCallBack(IAsyncResult ar) 
{ 
    serverSockect.EndSend(ar); 
    try 
    { 
     // Create a new buffer for each new BeginRecieve. 
     // If one global buffer was used, then it might get overwritten by 
     // a second request when the first request hasn't yet been completed. 
     byte[] buffer = new byte[16384]; 
     buffers.Enqueue(buffer); 
     serverSockect.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), null); 
    } 
    catch // the recieve failed 
    { 
     serverSockect.Close(); 
     ConnectedToServer = false; 
    } 
} 

static private void RecieveCallBack(IAsyncResult ar) 
{ 
    byte[] buffer = buffers.Dequeue(); 
    int len = serverSockect.EndReceive(ar); // len is usually some weird number 
    byte[] tempBuffer = new byte[len]; 
    Array.Copy(buffer, tempBuffer, len); 
    object returnObj = GetResponseObject(tempBuffer); 
    HandleResponse(returnObj); 
} 
+0

聽起來就像你只是得到1包,然後繼續前進,而不是等待其餘的 – BugFinder

+1

這聽起來像普通的數據包碎片;你有沒有檢查其餘的數據是否到達下一個數據包? 「ReceiveCallBack」之後,您是否嘗試繼續閱讀並不清楚。在使用TCP時,您絕不應該依賴於您發送它的相同作品中的數據。它提供的只是* stream *(當被使用時)將以正確的順序爲您提供所有正確的數據。 –

回答

0

由於BugFinder在評論中已經提到,TCP流可以被拆分成多個數據包。數據包將以正確的順序接收,但您無法確定緩衝區是否包含完整的消息。所以在你的接收方法中,你必須合併接收到的數據,直到你有一個完整的消息。

另一方面,短消息可以合併爲一個數據包。此兩者的混合(分組1包含消息1的第1部分,分組2包含消息1的第2部分和消息2的第1部分,分組3包含消息2的第2部分)是可能的。因此,您需要一個可以解析的協議來識別消息的結尾。

如果您有序列化的對象,最好的方法是在開始處設置序列化對象的長度。但是,如果沒有收到完整的長度數據,一定要能夠處理數據。在最糟糕的情況下,每個字節都可能來自自己的數據包!

+0

好吧,這是有道理的,我一直在依靠1發送,1接收思想集。你可能有代碼或鏈接有一個如何處理多個數據包的例子嗎?我不確定使用什麼方法/屬性來確定是否需要等待更多數據包。感謝您的回答,我已經更多地查看了數據包和套接字。 –

+0

請注意我正在序列化對象,而不僅僅是簡單的字符串。所以我不能簡單地在字符串的末尾添加「」。這是我在MSDN站點上看到的關於異步服務器和客戶端示例的示例。 https://msdn.microsoft.com/en-us/library/fx6588te%28v=vs.110%29.aspx - _server example_ –

+0

用提示更新瞭如何處理序列化對象的提示。 –