2

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 several 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!

joaquin
  • 82,968
  • 29
  • 138
  • 152
ylva
  • 23
  • 1
  • 4

5 Answers5

1

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.

João Neves
  • 937
  • 1
  • 6
  • 13
  • I saw this comment first, so made the changes in the code to catch the exception. Thanks a lot for the tip! - but the thing is that my port are still listening since before, so I cant test it without killing this first.. How can I stop it from listening? – ylva Feb 17 '11 at 15:48
  • I realized after some inhouse help here that it was the python process that was still running. To help others: In terminal, type $ ps -ef to see all processes. Find the PID number of the process to kill and kill it with $ sudo kill -9 PID. After that I could start the server again, and the Control+C worked as a charm to stop it! Thanks again! – ylva Feb 17 '11 at 16:16
1

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

jd.
  • 10,678
  • 3
  • 46
  • 55
  • Hi, same as below, will test this version also, but first I need to figure out how to stop the port from listening so I can restart my server with the changes. – ylva Feb 17 '11 at 15:49
  • If I understand you correctly, the port remains busy for more than one or two minutes? In that case, I'd make sure the process that holds the socket is really stopped. If you can't locate the process, try the lsof command, with sudo lsof -P|grep ":443" for example. – jd. Feb 17 '11 at 16:03
  • I decided to use the KeyboardInterrupt in the end. Thanks a lot anyway! Edit: saw your new comment now and yes - it was really the process that had to be killed! Thanks! :) – ylva Feb 17 '11 at 16:19
1

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.

0

On OSX you can kill the port(e.g. 8000) with:

kill `lsof -i :8000 | grep Python | cut -c8-11`

hth

zdys
  • 1
0

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....

bluszcz
  • 4,054
  • 4
  • 33
  • 52
  • I didnt get exactely this commant to work - but I tested netstat -an (as I saw here: http://stackoverflow.com/questions/2270343/cannot-bind-to-address-after-socket-program-crashes) and it says for *.443 that it is LISTENING. Need to kill it.. Do you know how..? Thanks for the help so far! – ylva Feb 17 '11 at 15:51
  • See comments on accepted answer for how I managed in the end. Thanks for the answer that gave me clues to solve it! – ylva Feb 17 '11 at 16:18