Song Tùng
Song Tùng

Reputation: 171

Python socketserver does not unbind automatically if KeyBoardInterrupted is raised

I am new to Python socket server programming, I am following this example to setup a server using the socketserver framework. Based on the comment, pressing Ctrl-C will stop the server but when I try to run it again, I get

OSError: [Errno 98] Address already in use

which makes me have to kill the process manually using the terminal.

Based on my understanding, KeyboardInterrupt is considered one type of exception in Python, and when an exception happens in a with block, Python will also call the __exit__() function to clean up. I have tried to create a __exit__() function in the TCP hanlder class but that does not seems to fix the problem.

Does anyone know a way to unbind the socket when an exception is raised?

server.py

import socketserver
from threading import Thread

class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        # just send back the same data, but upper-cased
        self.request.sendall(self.data.upper())
    
    # Self-written function to try to make Python close the server properly
    def __exit__(self):
        shutdown_thread = Thread(target=server.shutdown)
        shutdown_thread.start()
           

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    # Create the server, binding to localhost on port 9999
    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        # Activate the server; this will keep running until you
        # interrupt the program with Ctrl-C
        server.serve_forever()

Upvotes: 2

Views: 694

Answers (2)

kinshukdua
kinshukdua

Reputation: 1994

As @Tim Roberts explained that it's an artifact of TCP. Aside from his method you can also manually pass the SO_REUSEADDR flag by using

socket.setsockopt(socket.SO_REUSEADDR)

This might be useful when you're passing multiple socketopts or when you want something more familiar to low level networking in C.

Upvotes: 1

Tim Roberts
Tim Roberts

Reputation: 54718

This is not a Python thing, this is an artifact of TCP. A socket that seems to be closed is actually left in a partially open state even after the application has died. To get around that, use

socketterver.TCPServer.allow_reuse_address = True

before creating your server. This enables the SO_REUSEADDR socket option that overrides this behavior.

Upvotes: 3

Related Questions