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

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

1 ответ

Решение

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

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

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

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

Сокетное программирование вообще не тема для начинающих.

Другие вопросы по тегам