2016-08-22 4 views
-1

Итак, когда сервер отправляет менее 16384 байт, тогда клиент получает все данные с неполадкой. Но как только сервер отправляет больше, чем тогда, клиент получает странные суммы, например 6140. Он не всегда это делает, но большую часть времени он делает, но он делает это часто. Он очень редко получает полные 16384 байта.C# Сокеты: клиент не получает все байты при получении большого буфера

Сначала я подумал, что соединение просто займет много времени, чтобы отправить полную сумму, поэтому я установил тайм-аут приема на 30 секунд (30000 миллисекунд). Это ничего не решило. Каждый раз, когда я получаю данные, я использую новый массив байтов, чтобы он не перезаписывался другим BeginRecieve().

Единственное, что я могу придумать, это то, что аппаратное обеспечение (компьютер) не может хранить эти большие количества байтов в памяти и, следовательно, усекает буфер. У меня есть много кода, но это основа вещей:

код сервера (Только некоторые из них):

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); 
    } 
} 

Client Code (Только некоторые из них):

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 содержит часть 2 сообщения 1 и часть 1 сообщения 2, пакет 3 содержит часть 2 сообщения 2). Поэтому вам нужен протокол, который вы можете проанализировать, чтобы распознать конец сообщения.

Если у вас есть сериализованные объекты, лучшим способом было бы иметь в начале длину сериализованного объекта. Но не забудьте правильно обрабатывать данные, если не были получены полные данные для длины. В худшем случае каждый байт может попасть в собственный пакет!

+0

Хорошо, что имеет смысл, я полагался на набор 1 отправки, 1 прием. Возможно, у вас есть код или ссылка, в которой есть пример того, как обрабатывать несколько пакетов? Я не знаю, какой метод/свойства использовать для определения того, нужно ли мне ждать большего количества пакетов. Спасибо за ответ, я немного посмотрел на пакеты и сокеты. –

+0

Обратите внимание, что я сериализую объекты, а не просто строки. Поэтому я не могу просто добавить «» в конец строки. Это пример, который я видел на сайте MSDN для асинхронного сервера и клиентских примеров. https://msdn.microsoft.com/en-us/library/fx6588te%28v=vs.110%29.aspx - _server example_ –

+0

обновил ответ с подсказкой о том, как обрабатывать сериализованные объекты. –

 Смежные вопросы

  • Нет связанных вопросов^_^