Как неблокирующие Python сокеты получают ввод? - PullRequest
0 голосов
/ 25 марта 2020

Если у меня есть этот код, относящийся к разъему разблокировки, который называется sock

recv_data = sock.recv(1024)
        if recv_data:
            data.outb += recv_data
        else:
            print('closing connection to', data.addr)
            sel.unregister(sock)
            sock.close()

Что именно происходит? Чем оператор recv_data = sock.recv(1024) отличается от блокирующего и неблокирующего? Если программа не ожидает завершения этого оператора, как recv_data может иметь значение?

Редактировать: Полный код сервера:

import selectors
import socket
import types

host = "127.0.0.1"
port = 65432

def accept_wrapper(sock):
    conn, addr = sock.accept()
    print('accepted conneciton from', addr)
    conn.setblocking(False)
    data = types.SimpleNamespace(addr=addr, inb=b'', outb=b'')
    events = selectors.EVENT_READ | selectors.EVENT_WRITE
    sel.register(conn, events, data=data)

def service_connection(key, mask):
    sock = key.fileobj
    data = key.data
    if mask & selectors.EVENT_READ:
        recv_data = sock.recv(1024)
        if recv_data:
            data.outb += recv_data
        else:
            print('closing connection to', data.addr)
            sel.unregister(sock)
            sock.close()
    if mask & selectors.EVENT_WRITE:
        if data.outb:
            print('echoing', repr(data.outb), 'to', data.addr)
            sent = sock.send(data.outb)
            data.outb = data.outb[sent:]

sel = selectors.DefaultSelector()
lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
lsock.bind((host, port))
lsock.listen()
print('listening on', (host, port))
lsock.setblocking(False)
sel.register(lsock, selectors.EVENT_READ, data=None)

while True:
    events = sel.select(timeout=None)
    for key, mask in events:
        if key.data is None:
            # From the listening socket
            accept_wrapper(key.fileobj)
        else:
            # Client Socket
            service_connection(key, mask)

1 Ответ

0 голосов
/ 25 марта 2020

Если sock неблокирует, он повысит BlockingIOError, если в противном случае заблокируется. Вокруг кода не отображается try / except? Другой вариант - select.select - используется, чтобы убедиться, что есть данные, прочитанные для получения, перед вызовом recv.

Пример, предполагающий соответствующий сервер:

>>> from socket import *
>>> s=socket()
>>> s.connect(('localhost',5000))
>>> s.setblocking(0)
>>> s.recv(1024)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
BlockingIOError: [WinError 10035] A non-blocking socket operation could not be completed immediately

Редактировать:

С дополнительным кодом recv вызывается только тогда, когда sel.select сообщает EVENT_READ (данные готовы для чтения), поэтому recv не должен блокироваться. Он либо вернет данные, либо пустую строку. Последнее указывает на то, что розетка была закрыта.

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