My class contains a socket that connects to a server. Some of the methods of the class can throw an exception. The script I'm running contains an outer loop that catches the exception, logs an error, and creates a new class instance that tries to reconnect to the server.
Problem is that the server only handles one connection at a time (by design) and the "old" socket is still connected. So the new connection attempt hangs the script. I can work around this by forcing the old socket closed, but I wonder: why doesn't the socket automatically close?
When it is "stuck", netstat shows two sockets connected to the port. The server is waiting for input from the first socket though, it isn't handling the new one yet.
I run this against a dummy server that replies "error\n" to every incoming line.
EDIT: see my comment on Mark Rushakoff's answer below. An assert(False) [that I subsequently catch] from within the exception handler seems to force the socket closed.
import socket
class MyException(Exception):
pass
class MyClient(object):
def __init__(self, port):
self.sock = socket.create_connection(('localhost', port))
self.sockfile = self.sock.makefile()
def do_stuff(self):
self._send("do_stuff\n")
response = self._receive()
if response != "ok\n":
raise MyException()
return response
def _send(self, cmd):
self.sockfile.write(cmd)
self.sockfile.flush()
def _receive(self):
return self.sockfile.readline()
def connect():
c = MyClient(9989)
# On the second iteration, do_stuff() tries to send data and
# hangs indefinitely.
print c.do_stuff()
if __name__ == '__main__':
for _ in xrange(3):
try:
connect()
except MyException, e:
print 'Caught:', e
# This would be the workaround if I had access to the
# MyClient object:
#c.sock.close()
#c.sockfile.close()
EDIT: Here's the (ugly) server code:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.bind(('localhost', 9989))
s.listen(5)
(c,a) = s.accept()
f = c.makefile()
print f.readline()
f.write('error\n')
f.flush()
(c2,a) = s.accept()
f = c.makefile()
print f.readline()
s.close()