Может ли неблокирующий сокет вызвать BlockingIOError из устройства чтения / записи? - PullRequest
0 голосов
/ 11 апреля 2019

Может ли sock.recvfrom когда-либо поднять BlockingIOError с ридера? Например, ниже

sock.setblocking(False)

def reader()
    try:
        (data, addr) = sock.recvfrom(512)
    except BlockingIOError:
        # Can this ever be raised?

loop.add_reader(sock.fileno(), reader)

Аналогично, может ли sock.send когда-либо поднять BlockingIOError у писателя?

sock.setblocking(False)

def writer()
   try:
       bytes_sent = sock.send(data)
   except BlockingIOError:
       # Can this ever be raised?

loop.add_writer(sock.fileno(), writer)

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

1 Ответ

1 голос
/ 11 апреля 2019

Может ли [BlockingIOError в асинхронном ридере] вообще никогда не происходить, логически? Если это возможно, при каких обстоятельствах?

Ответ на этот вопрос почти наверняка будет зависеть от системы. Сам Python не предоставляет никаких гарантий по этому вопросу: такие функции, как os.read и socket.recv, просто проверяют значение, возвращаемое базовым системным вызовом, и, если это указывает на ошибку, продолжают преобразовывать системную ошибку в Исключение Python.

Таким образом, вопрос сводится к тому, может ли чтение из сокета потерпеть неудачу с EAGAIN или эквивалентным, если предыдущий опрос / выбор показал, что он был читаем (и эквивалент для записи). Хотя это, безусловно, звучит как ненормальная ситуация, select(2) man-страница явно предупреждает об этом в разделе BUGS:

В Linux select() может сообщать дескриптор файла сокета как «готовый к чтению», но, тем не менее, при последующем чтении блокируется. Это может, например, произойти, когда данные поступили, но при проверке они имеют неверную контрольную сумму и отбрасываются. Могут быть другие обстоятельства, при которых файловый дескриптор ложно сообщается как готовый. Таким образом, может быть безопаснее использовать O_NONBLOCK на сокетах, которые не должны блокировать.

В случае неблокирующих сокетов следует читать «тем не менее последующие блоки чтения» как «тем не менее последующее чтение завершается неудачно с EAGAIN», и предупреждение относится к этому вопросу. Эта проблема также не относится к select(); Страница справочника poll(2) также упоминает о ложных пробуждениях в разделе ошибок, обращаясь к руководству select(2) за подробностями.

Другими словами, переносимый код не должен полагаться на чтение из «читаемых» сокетов, никогда не повышающее BlockingIOError. Asyncio не полагается на него: он реагирует на EAGAIN, просто , не завершая будущее , и таким образом повторно приостанавливает сопрограмму, ожидающую чтения.

...