简体   繁体   中英

How do nonblocking Python Sockets receive input?

If I have this code relating to an unblocking socket called 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()

What exactly happens? How is the statement recv_data = sock.recv(1024) differ from blocking and nonblocking? If the program doesn't wait for that statement to complete, how does recv_data ever have value?

Edit: Full server code:

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)

If sock is non-blocking, it will raise BlockingIOError if it would block otherwise. Is there a try / except not shown around the code? Another option is select.select is used to make sure there is data read to receive before calling recv .

Example assuming appropriate server:

>>> 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

Edit:

With the additional code, recv is only called when sel.select reports an EVENT_READ (data ready to read) so recv should not block. It will either return data or an empty string. The latter indicates the socket was closed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM