Может ли асинхронный прием получить возврат без чтения всех запрошенных мною байтов? - PullRequest
1 голос
/ 09 июня 2009

Я читал статью в блоге Вадима Стецяка о том, как передавать сообщения переменной длины с асинхронными сокетами.

Он говорит:

Что ожидать, когда на сервер приходит несколько сообщений? При работе с несколькими сообщениями нужно помнить, что операция приема может возвращать произвольное количество байтов, считываемых из сети. Обычно этот размер составляет от 0 до указанной длины буфера в методах Receive или BeginReceive.

Так что, даже если я скажу BeginReceive прочитать 100 байтов, он может прочитать меньше этого и вернет ??? Я занимаюсь разработкой программного обеспечения с поддержкой сети (TCP / IP) и всегда получаю одинаковое количество байт, которое я запрашивал.

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

Может быть, это как-то связано с IP против TCP?

Ответы [ 3 ]

2 голосов
/ 10 июня 2009

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

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

0 голосов
/ 11 июня 2009

Да, это действительно странное поведение. Тем не менее, вот как я это вижу ... это может быть неправильно, но я пришел, чтобы объяснить это себе после долгих часов отладочной сессии:

Когда вы используете «Получить нормально» (синхронизировано), он читает n байтов, а затем возвращает… отлично. Когда вы используете BeginReceive (асинхронно), он вызывает вас, когда начинает , чтобы прочитать n байтов.

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

Я согласен с вами в том, что имя смешное.

удачи!

0 голосов
/ 11 июня 2009

Когда поступает кадр Ethernet, драйвер устройства Ethernet скопирует весь кадр в свою память, только после копирования всего кадра он сообщит верхним уровням (TCP). Уровень TCP затем копирует данные в свой буфер и вызывает уровень сокета. Уровень сокетов затем копирует доступные данные в свое буферное пространство, называемое буферами сокетов. наконец данные копируются в буфер пользователей, и процесс получает сигнал.

Каковы сценарии, в которых размер данных, возвращаемых функцией receive (), может быть меньше запрашиваемых данных - 1) Если кадр Ethernet меньше запрошенного размера 2) Если размер буфера TCP (который является общесистемным размером, может проверить параметр sysctl -net.ipv4.tcp_rmem в linux) меньше запрашиваемого размера. 3) Если размер буфера сокета (который является конкретным размером приложения, может быть установлен с помощью setsockopt () с использованием SO_RCVBUF) меньше запрошенного размера.

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

Уровень IP здесь не играет никакой роли.

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