Search code examples
pythonsocketsnonblocking

Trying to implement non-blocking python tcp multiple ports getting wierd exception


I'm trying to implement a non-blocking python tcp server which listens on multiple ports.

I found some code in this Stackover posting and modified it to listen on multiple sockets, so far, so good.

My code is as follows.

#!/usr/bin/python

import select
import socket

ports_list=[7777,7778]


def make_socket(number):
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  sock.bind(('', number))
  sock.listen(5)
  return sock


read_list= map(lambda x: make_socket(x), ports_list)

print(read_list)

print "Listening on port %s" % ports_list

while True:
    readable, writable, errored = select.select(read_list, [], [])
    for s in readable:
        if s in read_list:
            client_socket, address = s.accept()
            read_list.append(client_socket)
            print "Connection from", address
        else:
            data = s.recv(1024)
            if data:
                s.send(data)
            else:
                s.close()
                read_list.remove(s)

I test it by running netcat in another console

$ netcat localhost 7778
dsa

But it borks, like so:

/tcp_non_blocking_listener.py
[<socket._socketobject object at 0xb72804fc>, <socket._socketobject object at 0xb7280534>]
Listening on port [7777, 7778]
Connection from ('127.0.0.1', 41237)
Traceback (most recent call last):
  File "./tcp_non_blocking_listener.py", line 27, in <module>
    client_socket, address = s.accept()
  File "/usr/lib/python2.7/socket.py", line 202, in accept
    sock, addr = self._sock.accept()
socket.error: [Errno 22] Invalid argument

I'm just getting started on python non-blocking API, what is the idiomatic way to do something like this?


Solution

  • You mismatch not accepted sockets with already accepted.

    your fixed code (introduced list with notAccepted sockets):

    #!/usr/bin/python
    
    import select
    import socket
    
    ports_list=[7777,7778]
    
    
    def make_socket(number):
      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      sock.bind(('', number))
      sock.listen(5)
      return sock
    
    
    read_list= map(lambda x: make_socket(x), ports_list)
    
    print(read_list)
    
    print "Listening on port %s" % ports_list
    
    notAccepted = read_list[:]
    
    while True:
        readable, writable, errored = select.select(read_list, [], [])
        for s in readable:
            if s in notAccepted:
                client_socket, address = s.accept()
                read_list.append(client_socket)
                print "Connection from", address, client_socket
            else:
                data = s.recv(1024)
                if data:
                    s.send(data)
                else:
                    s.close()
                    read_list.remove(s)