Получение данных в TCP - PullRequest
6 голосов
/ 26 октября 2009

Если я отправляю 1000 байтов в TCP, это гарантирует, что получатель получит все 1000 байтов вместе? или, может быть, он сначала получит только 500 байтов, а позже он получит другие байты?

РЕДАКТИРОВАТЬ : вопрос возникает с точки зрения приложения. Если 1000 байтов собираются в один буфер до того, как они достигают приложения ... тогда мне все равно, если он будет фрагментирован таким образом ...

Ответы [ 10 ]

13 голосов
/ 26 октября 2009

См. Протокол управления передачей :

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

«Поток» означает, что нет границы сообщения с точки зрения получателя. Вы можете получить одно 1000-байтовое сообщение или одну тысячу 1-байтовых сообщений в зависимости от того, что находится внизу и как часто вы вызываете чтение / выбор.

Редактировать : Позвольте мне прояснить с точки зрения приложения. Нет, TCP не гарантирует, что при одном чтении вы получите все 1000 байтов (или 1 МБ или 1 ГБ) пакета, которые отправитель мог отправить. Таким образом, протокол над TCP обычно содержит заголовок фиксированной длины с общей длиной содержимого в нем. Например, вы всегда можете отправить 1 байт, который указывает общую длину содержимого в байтах, что будет поддерживать до 255 байт.

3 голосов
/ 26 октября 2009

Как указывалось в других ответах, TCP - это протокол stream - каждый отправленный байт будет получен (один раз и в том же порядке), но нет внутренних "границ сообщения" - все ли байты отправляются в одном .send вызове или нескольких вызовах, они все равно могут приниматься в одном или нескольких .receive вызовах.

Итак, если вам нужны «границы сообщений», вам нужно наложить их поверх потока TCP, то есть, по сути, на уровне приложения. Например, если вы знаете, что отправляемые вами байты никогда не будут содержать \0, строки с нулевым символом в конце будут работать нормально; Различные методы «экранирования» позволяют отправлять строки байтов, которые не подчиняются таким ограничениям. (Для этого существуют протоколы, но ни один из них не является широко распространенным или общепринятым)

2 голосов
/ 26 октября 2009

В своем сообщении вы решаете, сколько байтов должно содержать ваше сообщение. Например, в вашем случае это 1000. Ниже приведен код C # для запуска того же самого. Метод возвращает 1000 байт. Код сброса равен 0 байтам; Вы можете адаптировать его в соответствии со своими потребностями.

Использование:

strMsg = ReadData(thisTcpClient.Client, 1000, out bDisconnected);

Ниже приведен метод:

    string ReadData(Socket sckClient, int nBytesToRead, out bool bShouldDisconnect)
    {
        bShouldDisconnect = false;

        byte[] byteBuffer = new byte[nBytesToRead];
        Array.Clear(byteBuffer, 0, byteBuffer.Length);

        int nDataRead = 0;
        int nStartIndex = 0;

        while (nDataRead < nBytesToRead)
        {

            int nBytesRead = sckClient.Receive(byteBuffer, nStartIndex, nBytesToRead - nStartIndex, SocketFlags.None);

            if (0 == nBytesRead)
            {
                bShouldDisconnect = true;
                //0 bytes received; assuming disconnect signal
                break;
            }

            nDataRead += nBytesRead;
            nStartIndex += nBytesRead;
        }

        return Encoding.Default.GetString(byteBuffer, 0, nDataRead);
    }

Дайте нам знать, что это не помогло вам (0: Удачи.

2 голосов
/ 26 октября 2009

В основном, что касается TCP, он только гарантирует, что данные, отправленные с одного конца на другой конец, будут отправлены в том же порядке. Теперь обычно вам нужно иметь внутренний буфер, который продолжает работать до тех пор, пока не получит ваш 1000-байтовый «пакет». Поскольку упомянутая команда recv возвращает, сколько фактически было получено. Поэтому обычно вам необходимо реализовать протокол поверх TCP, чтобы убедиться, что вы отправляете данные с соответствующей скоростью. Потому что, если вы отправите () все данные за один проход, это приведет к перегрузке нижележащего сетевого стека, что вызовет сложности. Поэтому обычно в протоколе отправляется крошечный пакет подтверждения, подтверждающий отправку пакета в 1000 байтов.

1 голос
/ 26 октября 2009

Да, есть вероятность получения пакетов по частям. Надеюсь, что статья MSDN и следующий пример (взятый из статьи в MSDN для быстрого просмотра) будут вам полезны, если вы используете сокеты Windows.

void CChatSocket::OnReceive(int nErrorCode)
{
   CSocket::OnReceive(nErrorCode);

   DWORD dwReceived;

   if (IOCtl(FIONREAD, &dwReceived))
   {
      if (dwReceived >= dwExpected)   // Process only if you have enough data
         m_pDoc->ProcessPendingRead();
   }
   else
   {
      // Error handling here
   }
}
0 голосов
/ 26 октября 2009

Единственное, что гарантирует уровень TCP, - это то, что получатель получит:

  • все байты, переданные отправителем
  • в том же порядке

Нет никаких гарантий относительно того, как байты могут быть разделены на "пакеты". Все, что вы можете прочитать о MTU, фрагментации пакетов, максимальном размере сегмента или о чем-либо еще, находится ниже уровня сокетов TCP и не имеет значения. TCP предоставляет потоковую службу только .

Что касается вашего вопроса, это означает, что получатель может получить первые 500 байтов, а затем следующие 500 байтов позже. Или получатель может получать данные по одному байту за раз, если это то, что он запрашивает. По этой причине функция recv() принимает параметр, который сообщает ей, сколько данных возвращает , вместо того, чтобы сообщать , насколько большой пакет .

0 голосов
/ 26 октября 2009

TCP гарантирует, что они получат все 1000 байтов, но не обязательно по порядку (хотя это будет выглядеть так для получающего приложения) и не обязательно все сразу (если вы сами не создадите пакет и не сделаете так).

Тем не менее, для пакета размером до 1000 байтов есть большая вероятность, что он отправит один пакет, если вы делаете это за один вызов send, хотя для больших передач это может и не быть.

0 голосов
/ 26 октября 2009

Зависит от установленного MTU (Максимальная единица передачи). Если ваше установившееся соединение (после рукопожатия) ссылается на MTU в 512 байтов, вам потребуется два или более TCP-пакетов для отправки 1000 байтов.

0 голосов
/ 26 октября 2009

IP-пакеты могут быть фрагментированы во время повторной передачи.

Таким образом, конечный компьютер может получить несколько пакетов, которые будут собраны обратно стеком TCP / IP. В зависимости от используемого вами сетевого API - данные будут переданы you либо в собранном виде, либо в виде пакетов RAW.

0 голосов
/ 26 октября 2009

Протокол управления передачей гарантирует успешную доставку всех пакетов, требуя подтверждения об успешной доставке каждого пакета отправителю получателем. По этому определению приемник всегда будет получать полезную нагрузку в виде кусков, когда размер полезной нагрузки превышает MTU (максимальная единица передачи) .

Для получения дополнительной информации, пожалуйста, прочитайте Протокол управления передачей .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...