2

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?

Luc
  • 5,339
  • 2
  • 48
  • 48
Bryan Hunt
  • 3,685
  • 2
  • 24
  • 36

2 Answers2

3

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)
ddzialak
  • 1,042
  • 7
  • 15
0

As is accept().

For UDP, you don't have "connections", so there's no accept().

Use sendto() and recvfrom() and SOCK_DATAGRAM.

Other than whatever context the application may apply and/or embed in the payload, there is no relationship in the protocol between one UDP datagram and the next from the same host. No guarantees that multiple datagrams from the same host and the same source/dest addr/port tuple are related to the same client application. It's completely connectionless and therefore any state must be managed entirely by the application and the contents of the payload.

Owen
  • 1