Когда неблокирующий 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 имеет три возможных исхода:

  1. в буфере отправки → успешно и возвращает количество принятых байтов (возможно, меньше, чем вы просили).
  2. буфер отправки полностью в то время как вы звоните send.
    →если сокет блокируется,send блоки
    →если сокет не блокируется,send завершается с EWOULDBLOCK/EAGAIN
  3. произошла ошибка (например, пользователь вытащил сетевой кабель, Соединение прервано) →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 в сокет, если он на самом деле не блокирует это.

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