Alvaro
Alvaro

Reputation: 2327

Python multiprocessing and sockets not being closed

I'm experiencing an odd behaviour when using multiprocessing and socket on Python. I'm dealing with a piece of code similar that the one I'm posting below (I've simplified things a lot trying to be naive).

The code spawns three processes: one process does nothing, another process launches the third one, that will be listening on a socket. If I terminate the "listener" process, the socket still remains open (I can see it there with a netstat).

Does anyone have any hint why the socket is still opened? Is there any problem dealing with multiprocessing and sockets?

I'm using python 2.6.6 running on Linux.

Thank you very much, Alvaro.

import time
from multiprocessing import Process, Event

import socket

class Server(Process):
    def __init__(self, port):
        super(Server, self).__init__()

        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.bind(("127.0.0.1",port))
        self.s.listen(1)
        self.s.settimeout(10)
        self.is_stop = Event()
        self.is_stop.clear()

    def run(self):
        while not self.is_stop.is_set():
            print "Server: running (pid %s)" % self.pid 
            time.sleep(1)
        print "Server: exiting"

    def stop(self):
        self.is_stop.set()
        self.s.close()

class Launcher(Process):
    def __init__(self):
        super(Launcher, self).__init__()
        self.srv = Server(9999)
        self.srv.start()

    def run(self):
        print "Launcher pid %s" % self.pid
        while True:
            time.sleep(1)

    def stop(self):
        print "Launcher: I'm stopping the server"
        self.srv.stop()
        self.srv.terminate()
        self.srv.join()
        print "Launcher: server stopped"

class DoNothing(Process):
    def __init__(self):                
        super(DoNothing, self).__init__()

    def run(self):
        while True:
            time.sleep(1)


l = Launcher()
l.start()

dn = DoNothing()
dn.start()

time.sleep(2)

print " Stop launcher "
l.stop()

while True:
    time.sleep(1)

EDIT:

Relevant netstat -lnp output:

tcp        0      0 127.0.0.1:9999          0.0.0.0:*               LISTEN      7183/python

I've noticed that the pid shown in netstat changes from the parent process (when the process Server is running) to the Launcher's one (when the server is stopped).

Upvotes: 4

Views: 3285

Answers (2)

unutbu
unutbu

Reputation: 880777

To fix the immediate problem (of the socket not shutting down), add self.s.shutdown(socket.SHUT_RDWR) to the Server.stop method:

def stop(self):
    self.is_stop.set()
    self.s.shutdown(socket.SHUT_RDWR) 
    self.s.close()

Upvotes: 4

NPE
NPE

Reputation: 500893

I am no expert on the multiprocessing package, but it would appear that the Process constructor is called in the context of the parent process (i.e. before the fork). If that's the case, then it follows that it is the topmost process in your hierarchy that does the bind. The child processes probably inherit the socket.

What happens if you move everything that deals with self.s (bind et al) into Server.run?

Upvotes: 1

Related Questions