Working with a tcp server - following snippet creates the server
import threading
import socketserver
import time
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
#def __init__(self, a,b,c):
# super().__init__(request=a,client_address=b,server=c)
def setup(self):
pass
def handle(self):
pass
def finish(self):
pass
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
class Transport_Server:
def __init__(self):
# Port 0 means to select an arbitrary unused port
HOST, PORT = "0.0.0.0", 5001
self.server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
#with self.server:
ip, port = self.server.server_address
self.server_thread = threading.Thread(target=self.server.serve_forever)
# Exit the server thread when the main thread terminates
self.server_thread.daemon = True
self.server_thread.start()
print("Server loop running in thread:", self.server_thread.name)
def shutdown(self):
self.server.shutdown()
self.server_thread.join()
if __name__ == "__main__":
transport = Transport_Server()
print("Server started")
time.sleep(5)
print("Shutting down")
transport.shutdown()
print("Waiting")
time.sleep(5)
transport = Transport_Server()
print("Server restarted")
Works fine.
But if I shutdown the server with object.server.shutdown()
and then create a new instance of Transport_Server
I get
OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
CodePudding user response:
When a server is closed, the connection will not come to 'CLOSED' state immediately. instead, it will be in 'TIME_WAIT' state. to allow the client receive 'FIN_ACK' packet and to ttl down all delayed incoming packets.
During this 'TIME_WAIT' duration, we can't create new server in that address.
More details here: https://www.ietf.org/rfc/rfc793.txt
Checking the newly posted code above, server.shutdown()
is just not enough, if you are restarting the server again immediately. as it just tells the serve_forever()
to stop. but the ip address and port occupied stays in listening state.
when we add server.server_close()
it cleans up the server and releasing the address, making it ready for a restart.
You can find the documentation here.
Below the updated Transport_Server.shutdown()
function, which works fine.
def shutdown(self):
self.server.shutdown()
self.server_thread.join()
self.server.server_close()