Search code examples
pythonsocketstcp

Receive data only if available in Python sockets


I want to receive data only if it is available. like Serial.available() in Arduino. I want code like this:

if there is data:
     receive and print
else:
     print 'No data'

In fact, I do not want the program to stop just for receiving data.


Solution

  • You can call .setblocking(False) on a socket to disable blocking mode. The call will raise a BlockingIOError when it would otherwise block. But then you have to handle exceptions when you .accept() or .recv() on the socket and there is no connection ready or no data to receive.

    For example:

    try:
        data = s.recv(1024)
        print(data)
    except BlockingIOError:
        print('no data')
    

    select.select can be used to poll multiple sockets for data. Here's a quick example:

    import socket
    import select
    
    server = socket.socket()
    server.bind(('', 8000))
    server.listen()
    readables = [server] # list of readable sockets.  server is readable if a client is waiting.
    i = 0
    while True:
        # to_read will be a list of sockets with readable data
        to_read, to_write, errors = select.select(readables, [], [], 0)
        for sock in to_read: # iterate through readable sockets
            if sock is server: # is it the server?
                client, address = server.accept()
                print(f'\r{address}: connected')
                readables.append(client) # add the client
            else:
                # read from address client
                data = sock.recv(1024)
                if not data:
                    print(f'\r{sock.getpeername()}: disconnected')
                    readables.remove(sock)
                    sock.close()
                else:
                    print(f'\r{sock.getpeername()}: {data}')
        # a simple spinner to show activity
        i += 1
        print(r'/-\|'[i%4], end='\r', flush=True)
    

    Example where two clients connected, sent something and disconnected:

    ('127.0.0.1', 2983): connected
    ('127.0.0.1', 2983): b'hello'
    ('127.0.0.1', 2985): connected
    ('127.0.0.1', 2985): b'there'
    ('127.0.0.1', 2983): disconnected
    ('127.0.0.1', 2985): disconnected
    <spinner activity here>