Reputation: 2327
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
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
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