Почему не блокировать recv, пока не получит все данные? - PullRequest
8 голосов
/ 09 января 2012

Почему системный вызов recv не блокируется, пока не будут получены все данные?Каждый раз, когда я видел вызов recv, он находится в цикле while, который просто продолжает вызывать recv, пока все данные не будут там.Почему бы просто не иметь блок recv на первом месте?

Ответы [ 3 ]

9 голосов
/ 09 января 2012

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

Что касается того, почему это так по умолчанию, на ум приходит несколько причин:

  • Часто вы хотите, чтобы получил частичное чтение.Например, если вы постепенно отображаете данные по мере их поступления, или если вы передаете их в другое место, или если данные настолько велики, что вы не можете буферизовать все это в памяти сразу.В конце концов, если вы просто немедленно записываете в файл, вы заботитесь о том, чтобы разделить его на 200 записей, а не, скажем, на 150?
  • Иногда вы даже не знаете, сколько данных вам нужноначало.Рассмотрим протокол telnet, который был популярен во времена разработки API сокетов BSD.Обычно вы будете получать несколько байтов за раз, нет полей длины, указывающих, сколько данных ожидать, и, кроме того, вам нужно отобразить эти данные сразу .Блокировать не имеет смысла, пока вы не заполните здесь буфер.Аналогично с линейно-ориентированными протоколами, такими как SMTP или IMAP - вы не знаете, сколько длится команда, пока вы не получите ее все.
  • recv часто используется для сокетов дейтаграмм, где она получаетодна датаграмма, даже если она намного меньше, чем предоставленный буфер.Естественное расширение потоковых сокетов - просто возвращать столько, сколько вы можете, не дожидаясь.

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

4 голосов
/ 09 января 2012

В большинстве случаев вы не знаете, сколько данных составляют «все данные». Например, если вы получаете данные по линейно-ориентированному протоколу, длина строки может быть 10 или 65 байт.

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

Вы можете изменить флаги сокетов на блокирующие или неблокирующие.Ваш конкретный случай на самом деле не имеет ничего общего с блокировкой или не блокировкой.

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

Прочитайте http://www.scottklement.com/rpg/socktut/nonblocking.html, чтобы ознакомиться с блокирующим и неблокирующим IO.

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