boost :: asio отправляет данные быстрее, чем получает по TCP. Или как отключить буферизацию - PullRequest
2 голосов
/ 04 января 2012

Я создал клиент-серверную программу, клиент запускает экземпляр класса Writer, а сервер запускает экземпляр класса Reader.Затем Writer будет асинхронно записывать байты данных DATA_SIZE в устройство чтения каждые миллионы секунд USLEEP.

Каждый последующий запрос Writer async_write выполняется только в том случае, если был вызван обработчик «on write» из предыдущего запроса.

Проблема в том, что если Writer (клиент) записывает в сокет больше данных, чем Reader (сервер) способен принять, это выглядит следующим образом:

  • Writer начнет запись в (я думаю) системный буфер и, хотя Reader еще не получил данные, он вызовет обработчик «on write» без ошибки.

  • Когда буфер заполнен, boost :: asio больше не будет запускать обработчик «при записи», пока буфер не станет меньше.

  • Между тем, Reader все еще получаетнебольшие порции данных.

  • Тот факт, что Reader продолжает получать байты после закрытия программы Writer, похоже, подтверждает правильность этой теории.

Мне нужно предотвратить эту буферизацию, потому что данные должны быть «в реальном времени» (насколько это возможно).

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

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

NOTE1 : Прежде чем я начал экспериментировать с асинхронными операциями в библиотеке asio, я реализовал эту же самуюсценарий, использующий потоки, блокировки и asio :: сокеты и не испытавший такой буферизации в то время.Мне пришлось переключиться на асинхронный API, потому что asio, по-видимому, не позволяет прерывать синхронные вызовы по времени.

NOTE2 : Вот рабочий пример, демонстрирующий проблему: http://pastie.org/3122025

EDIT : я сделал еще один тест, в моем NOTE1 я упоминал, что когда я использовал asio :: iosockets, у меня не было этой буферизации.Поэтому я хотел быть уверенным и создал этот тест: http://pastie.org/3125452 Оказывается, Буферизация есть событие с asio :: iosockets , поэтому должно было быть что-то еще, что заставило его пойтиплавно, возможно ниже FPS.

1 Ответ

2 голосов
/ 04 января 2012

TCP / IP определенно предназначен для максимизации пропускной способности, поскольку целью большинства сетевых приложений является передача данных между хостами. В таких сценариях ожидается, что передача N байтов займет T секунд, и, очевидно, не имеет значения, если получатель немного медленно обрабатывает данные. На самом деле, как вы заметили, протокол TCP / IP реализует скользящее окно, которое позволяет отправителю буферизовать некоторые данные, чтобы они всегда были готовы к отправке, но оставляет конечному управлению дросселирование до получателя. Приемник может двигаться на полной скорости, шагать сам или даже приостанавливать передачу.

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

Очевидно, что при таком подходе ваш компромисс состоит в том, что каждый отправленный пакет находится ближе к реальному времени отправителя, но вы ограничиваете объем передаваемых данных, слегка увеличивая общую пропускную способность, используемую вашим протоколом (т. Е. Дополнительные управляющие сообщения). , Также имейте в виду, что «близко к реальному времени» является относительным, потому что вы все равно столкнетесь с задержками в сети, а также с способностью получателя обрабатывать данные. Таким образом, вы также можете взглянуть на конструктивные ограничения вашего конкретного приложения, чтобы определить, насколько «близким» вам действительно нужно быть.

Если вам нужно быть очень близко, но в то же время вас не волнует потеря пакетов из-за того, что старые пакетные данные заменяются новыми данными, тогда UDP / IP может быть лучшей альтернативой. Тем не менее, а) если у вас есть надежные требования к доставке, вы можете в итоге заново изобрести часть колеса tcp / ip и б) иметь в виду, что определенные сети (корпоративные брандмауэры) имеют тенденцию блокировать UDP / IP, в то же время разрешая трафик TCP / IP и ) даже UDP / IP не будет точно в реальном времени.

...