0
votes

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
why not using thread? the first socket won't block the other socket.omri_saadon
Your question is somewhat vague, but yes its possible, you need another thread, preferably a thread for each socket. Try wrapping the socket functionality in a new class, inherit that class from Thread and then just make a new class instance for each portDan
Are you using an existing python web server or writing your own? I wouldn't use a socket for receiving gui data personally. I think you are looking for interprocess communications such as D-Bus, XML-RPC and others.NuclearPeon
Yes, its safe to send data from python on one socket and receive it in Java. Its also considered a good option for Inter-process communication which is what you are explaining that you are doing hereDan
You can make listen / accept not block by setting socket.setblocking(0) on the listening socket(s). Then you can use select 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--

2 Answers

0
votes

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.

0
votes

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.