Close/restart socket in Python
I'm about to do a simple testimplementation to use PagSeguro (brazilian "PayPal"), and for this I downloaded their Python server to do tests on my localhost. I work on a Mac, have a XAMPP server (Apache and MySQL parts on during my process).
My problem should be very simple for someone who knows Python and sockets etc, and I did found a lot of clues in my information searches. However - with my own poor knowledge in this area, I wasn't able to put two and two together to fix it.
Short question: How do I free a socket (from Terminal) whos program quit before it had closed the socket. Alt - how do I make a Python function for me to call when I want to close the socket and stop/restart the server.
Scenario: I start the server (In terminal with #: sudo python ./PagSeguroServer.py) and it works fine, I did some of the tests I wanted to. Then, I needed to change some settings for the server, and to make it work i need to restart the server. I resolved by closing the terminal window, but then when I reopen and type the same command to start the server again I get the "socket.error: [Errno 48] Address already in use". Ok I can see why but not how to fix, so I Google that, and find the tip to add
socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
in the code. Looked at the Python class and tried to put it there to my best knowledge (as below). However, didn't solve my problem. Since my "search and puzzle" doesnt seem to be able to help me - I'm now giving it up and posting this customized question instead!
This is part of the server code:
class SecureHTTPServer(HTTPServer):
'''Servidor HTTPS com OpenSSL.'''
def __init__(self, server_address, HandlerClass,fpem):
BaseServer.__init__(self, server_address, HandlerClass)
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.use_privatekey_file (fpem)
ctx.use_certificate_file(fpem)
self.socket = SSL.Connection(ctx, socket.socket(self.address_family,
self.socket_type))
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_bind()
self.server_activate()
....
def run(HandlerClass = HTTPSHandler, ServerClass = SecureHTTPServer):
'''Roda o servidor'''
server_address = ('', 443) # (address, port)
httpd = ServerClass(server_address, HandlerClass, fpem)
httpd.serve_forever()
if __name__ == '__main__':
run()
Note: One time I actually did managed to reopen it - it was before I added the setsockopt call, and I got the feeling that the socket had closed after a timeout - read about that somewhere. This however doesn't seem to happen again - have waited and tried sever开发者_运维百科al times.
Edit: In the end this is how I resolved: Needed to kill the python process that was holding the socket (see comment on jd's answer), then added the KeyboardInterrupt catch to be able to close the socket correctly. Thanks all!
If you're using Ctrl+C to close the process, you could try catching the KeyboardInterrupt exception (or even better, handle the SIGINT signal) in your code and cleanly close the socket before exiting.
Of course, this won't prevent you from killing your application in some other manner and having a stale socket, but you can try to handle those cases as well.
You could create a function that closes the socket properly and register it to be run at program termination using atexit.register()
. See http://docs.python.org/library/atexit.html
Use the following command in a terminal window to kill the TCP port 28355:
npx kill-port 28355
In my python socket server script I used the following lines:
import os os.system("npx kill-port 28355")
This command solves the "Address already in use" error. It was the only solution that solved the error out of all the other solutions I found, like enabling the SO_REUSEADDR option.
AFAIR SO_REUSEADDR works a bit different.
But what you should start with - when you kill your working server type
netstat -tapdn |grep PORT
and replace PORT with PORT of yoiur application
Than you will get info about state of the socket....
On OSX you can kill the port(e.g. 8000) with:
kill `lsof -i :8000 | grep Python | cut -c8-11`
hth
精彩评论