TCP-сервер получает больше данных, чем ожидалось

У меня есть серверно-клиентское приложение, в котором клиент передает данные изображения на сервер. У меня есть следующая структура:

Клиент:

private void SerializeAndSendMessage(Message msg) {
        BinaryFormatter formatter = new BinaryFormatter();
        MemoryStream stream = new MemoryStream();
        formatter.Serialize(stream, msg);
        byte[] buffer = stream.ToArray();

        if (clientSocket != null)
        {
            if (clientSocket.Connected)
            {
                clientSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, SendCallback, null);
            }
        }
    }

private void SendCallback(IAsyncResult ar) {
        try
        {
            clientSocket.EndSend(ar);
            Debug.WriteLine("Message sent.");
        }
        catch (Exception ex)
        {
            //
        }
    }

Сервер:

  private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            int received = clientSocket.EndReceive(ar);
            Array.Resize(ref buffer, received);
            BinaryFormatter formatter = new BinaryFormatter();

            MemoryStream stream = new MemoryStream(buffer);

            object obj = null;
            stream.Position = 0;
            try
            {
                obj = formatter.Deserialize(stream);
            }
            catch (Exception ex )
            {
               //
            }

            // processing data

            Array.Resize(ref buffer, clientSocket.ReceiveBufferSize);
            clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
        }
        catch (Exception ex)
        {
            //
        }
    }

Что я ожидаю:

  1. сервер начинает принимать данные от клиента
  2. клиент отправляет данные с размером X
  3. сервер получает данные размером X и начинает их обрабатывать
  4. тем временем клиент все еще отправляет данные
  5. сервер не получает эти данные
  6. сервер закончил обработку полученных данных и теперь начинает получать от клиента
  7. перейти 2

Что происходит:

  1. сервер начинает принимать данные от клиента
  2. клиент отправляет данные с размером X
  3. сервер получает данные размером X и начинает их обрабатывать
  4. тем временем клиент все еще отправляет данные
  5. сервер не получает эти данные
  6. сервер закончил обработку полученных данных и теперь начинает получать от клиента
  7. клиент отправляет N-й пакет размера X
  8. сервер получает данные размера M*X

Это, очевидно, может привести к заполнению буфера на сервере и невозможности десериализации отправленных пакетов. Что мне не хватает? Что я могу сделать, чтобы добиться работы, описанной выше?


person Community    schedule 21.07.2015    source источник
comment
Попробуйте прочитать основы сокетов. Один Send() не равен одному Receive(). Вам нужен протокол приложения/фрейминга. Таких вопросов много.   -  person CodeCaster    schedule 21.07.2015


Ответы (1)


TCP — это потоковый протокол. Если вы выполняете несколько операций отправки на стороне клиента друг за другом, TCP будет объединять их в один сегмент, поскольку он пытается заполнить значение mtu.

TCP отправит, если mtu заполнен, или если истекает непрерывный таймер 50 мс, или если сам клиент должен подтвердить пакет, который он получил от сервера.

TCP — очень сложный протокол. Там также есть алгоритм, который вычисляет размер окна. Также этот размер окна влияет на размер сегментов, получаемых на стороне клиента.

Суть в том, что, поскольку TCP является потоковым протоколом, нет понятия пакета, который вы получаете через сокет. Вы получаете произвольное количество байтов, которые вы должны сами добавить в какой-то буфер приема, в зависимости от того, что вы делаете. Если вам нужны пакеты, вы должны добавить данные, которые вы отправляете, с полем длины, а также учитывать длину на сервере. Это, конечно, усложняет код. Или, если вы хотите, чтобы это было просто, просто используйте UDP. UDP поддерживает пакеты, и то, что вы отправляете, если пакет не потеряется где-то, будет получено получателем того же размера. Но UDP ненадежен, пакет может потеряться. TCP надежен, ориентирован на соединение, но более сложен.

Программирование сокетов в целом не тема для начинающих.

person Philip Stuyck    schedule 21.07.2015