Вопрос

Я использую розетки Berkley и TCP (Sock_Stream розетки).

Процесс:

  1. Я подключаюсь к удаленному адресу.
  2. Я отправляю сообщение ему.
  3. Я получаю сообщение от него.

Представьте, что я использую следующий буфер:

char recv_buffer[3000];
recv(socket, recv_buffer, 3000, 0);

Вопросы:

  • Как я могу знать, если после вызова Recv первый раз, когда прочитанный буфер пуст или нет? Если это не пусто, мне пришлось бы позвонить Recv снова, но если я сделаю это, когда он пуст, я бы заблокировал его за много времени.
  • Как я могу узнать, сколько байтов я читал в Recv_Buffer? Я не могу использовать strlen, потому что сообщение, которое я получаю, может содержать нулевые байты.

Спасибо.

Это было полезно?

Решение

Как я могу знать, если после вызова Recv первый раз, когда прочитанный буфер пуст или нет? Если это не пусто, мне пришлось бы позвонить Recv снова, но если я сделаю это, когда он пуст, я бы заблокировал его за много времени.

Вы можете использовать select или poll Системные вызовы вместе с вашим дескриптором сокета, чтобы сказать, если есть данные, ожидающие чтения из сокета.

Тем не менее, обычно должен быть согласованный протокол, который следуют как отправитель, так и получатель, чтобы обе стороны знали, сколько данных должно быть передано. Например,, возможно, отправитель сначала отправляет 2-байтовое целое число, указывающее количество байтов, которые он отправит. Затем приемник сначала читает это 2-байтовое целое число, чтобы он знал, сколько больше байтов читать из сокета.

Независимо от того, как указано ниже Tony, надежное приложение должно использовать комбинацию информации о длине в заголовке, в сочетании с опросом к розетке для дополнительных данных перед каждым вызовом recv, (или использование неблокирующего розетки). Это предотвратит заблокировать ваше приложение в том случае, если, например, вы знаете (от заголовка), что все еще должно быть 100 байтов, оставшихся для чтения, но Peer не может отправлять данные по какой-либо причине (возможно, Peer Computer был неожиданно отключить), что вызывает recv Вызов блокировать.

Как я могу узнать, сколько байтов я читал в Recv_Buffer? Я не могу использовать strlen, потому что сообщение, которое я получаю, может содержать нулевые байты.

То recv Системный вызов вернет количество чтения байтов или -1, если произошла ошибка.

С страницы человека для Recv (2):

RECV] Возвращает количество полученных байтов или -1, если произошла ошибка. Возвращаемое значение будет 0, когда Peer выполнил упорядоченное отключение.

Другие советы

Как я могу знать, если после вызова Recv первый раз, когда прочитанный буфер пуст или нет?

Даже впервые (после принятия клиента) RECV может заблокировать и отключить, если клиентское соединение было потеряно. Вы должны либо:

  • использовать select или poll (BSD розетки) или какой-то эквивалент, специфичный ОС, который может сказать вам, есть ли данные, доступные на определенных дескрипторах сокетов (а также условия исключения, а также буферное пространство, которое вы можете написать больше выходов)
  • Вы можете установить розетку, чтобы быть неблокированием, так что recv вернет только все, что будет немедленно доступно (возможно, ничего)
  • Вы можете создать тему, которую вы можете позволить себе иметь блок recvпознание других потоков будет выполнять другую работу, которую вы обеспокоены

Как я могу узнать, сколько байтов я читал в Recv_Buffer? Я не могу использовать strlen, потому что сообщение, которое я получаю, может содержать нулевые байты.

recv() Возвращает количество чтения байтов или -1 по ошибке.

Обратите внимание, что TCP является Байтовый поток Протокол, который означает, что вы гарантированно только сможете прочитать и записать байты из него в правильном порядке, но границы сообщения не гарантированы. Итак, даже если отправитель сделал большую одностороннюю запись в свой сокет, он может быть фрагментирован по пути и прибыть в несколько небольших блоков, или несколько меньших send()/write()S может быть консолидирован и извлечен одним recv()/read().

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

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

  1. Если то recv() Возвращает менее 3000 байтов, то вы можете предположить, что буфер чтения был пуст. Если он возвращает 3000 байтов в вашем 3000 байтовом буфере, то вам лучше знать, продолжать. Большинство протоколов включают в себя некоторые вариации на TLV - тип, длину, значение. Каждое сообщение содержит индикатор типа сообщения, некоторая длина (возможно, подразумеваемая типом, если длина фиксируется), и значение. Если на чтении данных вы получили, вы обнаружите, что последнее устройство неполное, вы можете предположить, что нужно прочитать. Вы также можете сделать гнездо в неблокирующем сокет; тогда recv() Потерпит неудачу с eaegain или ewouldblock, если нет данных, прочитанных для чтения.

  2. То recv() Функция возвращает количество чтения байтов.

IOCTL () С опцией Fionread сообщает вам, сколько данных в настоящее время можно прочитать без блокировки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top