I am making a python server that should handle connection from remote hosts on port 9090 and connection only from localhost (a GUI sending data) on port 9091. I think the problem is in socket.listen(backlog), because this blocks everything. So there is a way to make socket1.listen(backlog) and socket2.listen(backlog) running at the same time? Also, is it a good, and above all safe, idea to make a socket for receiving data from a GUI (written in Java)?
2 Answers
This can be done in C: Listen to multiple ports from one server
and C++: Create multiple listening sockets
so you should be able to do this in Python.
The only thing that would make this not safe is if your server performs a dangerous activity in response to the GUI, but you can probably add code to check and protect against hacks.
I am using python2.7.3
, and as stated in my comment I couldn't reproduce the listen
blocking issue.
Notes:
- for the simplicity's sake I am only using
IPv4
sockets - I included
Python
's prompter in the code to show that it didn't block - regarding eventual security concerns: the socket (
s_local
) listening on 9091, only accepts connections from localhost (from other hosts will fail)
Here's a snippet from a CentOS5 machine:
>>> import socket
>>> s_global = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s_global.bind(("", 9090))
>>> backlog = 0xFF
>>> s_global.listen(backlog)
>>> s_local = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s_local.bind(("127.0.0.1", 9091))
>>> s_local.listen(backlog)
>>>
and here's some output on the same machine:
netstat -an | grep 909
tcp 0 0 0.0.0.0:9090 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:9091 0.0.0.0:* LISTEN
As seen, both server sockets are listening for connections.
Now, if something is wrong in my environments (some reading revealed that by default sockets are blocking by default), after creating each socket, you could add (as specified in one comment) the following line(s):
for s_global
s_global.setblocking(0)
for s_local
s_local.setblocking(0)
Now in order to receive incoming connections from both sockets, you should use Python
's select module (used for async IO) with no need for other threads; your server app should constantly listen for connections, something like:
TIMEOUT = 1 #seconds
terminate = False # variable to be modified externally to end the loop
listening_sockets = [s_global, s_local]
while (not terminate):
notified_socket_list = select.select(listening_sockets, [], [], TIMEOUT)[0]
for notified_socket in notified_socket_list:
incoming_socket, addr = notified_socket.accept()
handle(incoming_socket, addr)
Note: worth being mentioned: epoll(select.epoll
) is performance-wise preferred to select(select.select
) but i haven't tried it yet.
Now, regarding the connections handling function(handle): if your server is designed only for educative purposes, you can leave it as it is, but if your server is designed to accept lots of simultaneous connections and lots of data exchange from/to each client, you should handle each connection in a separate thread(this is a general advice that doesn't apply to Python
because of its GIL, sometimes threads only slow things down)/process as done in SocketServer.py - part of Python's standard library.
@Edit1 - reply to 1st comment:
It's simple, all you have to do is modify a little bit the inner for
loop:
for notified_socket in notified_socket_list:
incoming_socket, addr = notified_socket.accept()
if notified_socket == s_global:
handle_global(incoming_socket, addr)
else:
handle_local(incoming_socket, addr)
or you can use my original solution and do the differentiate the connections in handle: the addr
argument contains the (local) port that the socket connected to; you can test it and depending on its value (9090 or 9091) handle the connection differently.
interprocess communications
such as D-Bus, XML-RPC and others. – NuclearPeonlisten
/accept
not block by settingsocket.setblocking(0)
on the listening socket(s). Then you can useselect
to wait for events. There are some details to take care of, but it should be fairly easy. Of course, you can also use a library that does such stuff for you. One option is twisted: twistedmatrix.com/trac. See their echo server example (twistedmatrix.com/trac/#echoserver) to get started. – Alok--