Получение всех данных, отправленных с сокетами C - PullRequest
1 голос
/ 26 февраля 2011

Если я пишу сервер, как я могу реализовать функцию получения, чтобы получить все данные, отправленные конкретным клиентом, если я не знаю, как этот клиент отправляет данные?
Я использую протокол TCP / IP.

Спасибо заранее.

Ответы [ 6 ]

4 голосов
/ 26 февраля 2011

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

В зависимости от вашего приложения, это может быть достаточно.Если нет, то вам придется разработать протокол и поверить, что ваши клиенты будут соблюдать правила этого протокола.Хорошим подходом является отправка клиентом заголовка, в котором говорится, сколько байтов он планирует отправить;или отправка какого-либо специального индикатора «Хорошо, это все, что я имел в виду», также возможно (хотя, если вы сделаете это таким образом, вы должны остерегаться ложных срабатываний, если специальный индикатор может случайно появиться внутри самих данных)

1 голос
/ 26 февраля 2011

TCP основан на потоке, поэтому понятия «завершенное сообщение» не существует: он передается по протоколу более высокого уровня (например, HTTP), или вам придется изобретать его самостоятельно. Если бы вы могли свободно использовать UDP (на основе дейтаграмм), то не было бы необходимости выполнять send () несколько раз или receive (). Более новый протокол SCTP также изначально поддерживает концепцию сообщения.

В TCP для реализации сообщений необходимо сообщить получателю размер сообщения. Это могут быть первые несколько байтов (обычно 2, поскольку это разрешает сообщения размером до 64 КБ - но вы должны быть осторожны с порядком байтов, если вы можете обмениваться данными между различными системами), или это может быть что-то более сложное. HTTP, например, имеет полный набор правил , по которым получатель определяет длину сообщения. Одним из них является HTTP-заголовок Content-Length, который содержит строку, представляющую количество байтов в теле сообщения. HTTP-сообщения только для заголовков просто отделяются пустой строкой. Как видите, простых (или стандартных) ответов не существует.

1 голос
/ 26 февраля 2011

Вы можете объединить размер с вашими данными в одном буфере и один раз позвонить. Люди обычно используют первые 2 байта для размера данных в пакете. Вот так

|size N (2 bytes) | data (N bytes) |

В этом случае вы можете содержать пользовательские данные длиной 65535 байт.

Поскольку TCP не сохраняет границы сообщения, не имеет значения, сколько раз вы вызываете send. Вы должны звонить на получение до тех пор, пока не получите N size(2 bytes), тогда вы можете продолжать звонить на получение, пока не получите N bytes data отправленные вами сообщения.

ОБНОВЛЕНИЕ: это просто пример, показывающий, как проверить границу сообщения в TCP. Безопасность / Шифрование - это совсем другая история, и она заслуживает новой темы. Тем не менее, не просто скопируйте этот дизайн. :)

1 голос
/ 26 февраля 2011

Это зависит от того, как вы хотите создать свой протокол.

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

1 голос
/ 26 февраля 2011

Один вызов send не равен одному вызову recv. Либо отправьте заголовок, чтобы получатель знал, сколько данных ожидать, либо отправьте какое-нибудь значение дозорного, чтобы получатель знал, когда прекратить чтение.

0 голосов
/ 26 февраля 2011

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

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

Например, заголовки HTTP заканчиваются двойной последовательностью \r\n и длиной тела сообщения.можно получить из заголовка Content-Length.

...