Когда неблокирующий send () передает только частичные данные, можем ли мы предположить, что он вернет ewouldblock следующий вызов?
два случая хорошо документированы на man-страницах для неблокирующих сокетов:
- Если send () возвращает ту же длину, что и буфер передачи,всей передачи успешно завершено, и сокет может или не может быть в состоянии возврата EAGAIN / EWOULDBLOCK следующего вызова с >0 байтами для передачи.
- Если send () возвращает -1, а errno-EAGAIN/EWOULDBLOCK,ни одна передача!--5--> закончил, и программа должна подождать, пока сокет готов для получения дополнительных данных (EPOLLOUT в случае epoll).
что не документировано для неблокирующих сокетов:
- If send () возвращает положительное значение, меньшее размера буфера.
можно ли предположить, что send() вернет EAGAIN/EWOULDBLOCK еще на один байт данных? Или неблокирующая программа должна попытаться отправить () еще раз, чтобы получить окончательный EAGAIN/EWOULDBLOCK? Я беспокоюсь о том, чтобы поставить EPOLLOUT наблюдатель на сокете, если он на самом деле не находится в состоянии "блокирует", чтобы ответить на него.
очевидно, что последняя стратегия (попытка снова получить что-то убедительное) имеет четко определенное поведение, но она более многословна и наносит удар по производительности.
2 ответов
вызов send
имеет три возможных исхода:
- в буфере отправки → успешно и возвращает количество принятых байтов (возможно, меньше, чем вы просили).
- буфер отправки полностью в то время как вы звоните
send
.
→если сокет блокируется,send
блоки
→если сокет не блокируется,send
завершается сEWOULDBLOCK
/EAGAIN
- произошла ошибка (например, пользователь вытащил сетевой кабель, Соединение прервано) →
send
сбой с другой ошибкой
если количество байтов, принятых send
меньше суммы, которую вы просили, следовательно, это означает, что буфер отправки теперь полностью заполнен. Однако это чисто косвенные и неавторитарные в отношении любых будущих призывов к send
.
Информация, возвращенная send
- Это просто "снимок" текущего состояния в то время, когда вы вызывали send
. К тому времени send
вернулся или в момент вызова send
опять же, эта информация уже может быть устаревшей. Сетевая карта может поместить дейтаграмму на провод, пока ваша программа находится внутри send
, или наносекундой позже, или в любое другое время-нет никакого способа узнать. Вы узнаете, когда следующий вызов будет успешным (или когда это не так).
другими словами, это не подразумевает, что следующий вызов к send
вернутся EWOULDBLOCK
/EAGAIN
(или если сокет не был неблокирующий). Пытались, пока что вы назвали "получение убедительных EWOULDBLOCK
" - это правильно.
Если send () возвращает ту же длину, что и буфер передачи, вся передача завершена успешно, и сокет может находиться или не находиться в состоянии блокировки.
нет. Сокет остается в режиме, в котором он был: в этом случае неблокирующий режим, предполагаемый ниже.
Если send () возвращает -1, а errno-EAGAIN/EWOULDBLOCK, ни одна передача не завершена, и программе нужно подождать, пока сокет не будет заблокирован больше.
пока буфер отправки не больше. Сокет остается в неблокирующем режиме.
If send () возвращает положительное значение, меньшее размера буфера.
в буфере отправки сокета было только столько места.
можно ли предположить, что send() будет блокировать еще один байт данных?
небезопасно "предполагать, что [это] будет блокировать" вообще. Не будет. Это ... в неблокирующем режиме. EWOULDBLOCK означает это бы заблокирован в блокирующем режиме.
или неблокирующая программа должна попытаться отправить () еще раз, чтобы получить окончательный EAGAIN/EWOULDBLOCK?
Это зависит от вас. API работает в зависимости от вашего решения.
Я беспокоюсь о том, чтобы поместить наблюдателя EPOLLOUT в сокет, если он на самом деле не блокирует это.
Это не блокировка на этом". Он ничего не блокирует. Он находится в неблокирующем режиме. В этот момент буфер отправки был заполнен. Через мгновение он может оказаться совершенно пустым.