How to properly close socket in both client and server (python)

10,010

It looks like what you are looking for is an graceful shutdown. First your code does not work because you are closing socket immediately after calling shutdown.

The rule is that in a graceful shutdown, both sides must be aware of the shutting down and have acknowledged it before any actually closes the socket. I only found reference for that in this MSDN page, even if it is cited on this other SO answer.

Here is a simplified presentation of what is better explained if referenced page (I do not know how to properly format tables in SO :-( ) :

  • part 1 issues shutdown(socket.SHUT_WR) to notify it wants to terminate connexion, and continues to read from socket
  • part 2 receives end of file indication on socket (empty read), and can still send any remaining data - it then calls in turn shutdown(socket.SHUT_WR)
  • part 1 receives end of file on socket and knows that other part has terminated using connection
  • both parts can then close the socket

Remark : it does not matter if part 2 actually closes socket before part 1 received end of file, because part 1 was already only waiting for an indication of termination : no data can have been lost

Share:
10,010
wantToLearn
Author by

wantToLearn

Updated on June 05, 2022

Comments

  • wantToLearn
    wantToLearn almost 2 years

    I am writing 2 scripts in python.

    1. Client.py
    2. Server.py

    There is a socket between the client and server. The scenario is this:
    I am having one client that ask to close the program therefore it should inform the server which by then will inform the other client, therefore I need to close the socket from client (1) to the server and then close the socket from the server to other client (imagin yourself a game of 2 people that one ask to exit the game).

    I am doing it like that.In Client.py:

    # send the request to the server
    eNum, eMsg = Protocol.send_all(self.socket_to_server, msg)
    if eNum:
        sys.stderr.write(eMsg)
         self.close_client()
    self.socket_to_server.shutdown(socket.SHUT_WR) 
    exit(0)
    

    then in the code of Server.py:

    # get the msg from the client that calleds
            num, msg = Protocol.recv_all(self.players_sockets[0])
    
            # case of failure
            if num == Protocol.NetworkErrorCodes.FAILURE:
                sys.stderr.write(msg)
                self.shut_down_server()
    
            # case it was disconnected
            if num == Protocol.NetworkErrorCodes.DISCONNECTED:
                print msg
                self.shut_down_server()
    
    
    
            technical_win = ("exit" == msg)
    
    
    
            # send the msg to the client needed to call    
            eNum, eMsg = Protocol.send_all(self.players_sockets[1],msg)
            if eNum:
                sys.stderr.write(eMsg)
                self.shut_down_server()
    
            # case end of game (winning or asking to exit)
            if technical_win:
                self.shut_down_server()
    

    while self.shut_down_server()is:

    def shut_down_server(self):
    
            # close socket of one of the player
            self.players_sockets[0].shutdown(socket.SHUT_RDWR)
            self.players_sockets[0].close()
    
            # close socket of one of the player
            self.players_sockets[1].shutdown(socket.SHUT_RDWR)
            self.players_sockets[1].close()     
    
            # clean up
            exit(0)  
    

    When the server send the msg that the other player ask to exit the client get it and doing the same as I showed in the begining.

    unfortunately it is not working because when the server perform the code:

    num, msg = Protocol.recv_all(self.players_sockets[0])
    
            # case of failure
            if num == Protocol.NetworkErrorCodes.FAILURE:
                sys.stderr.write(msg)
                self.shut_down_server()
    
            # case it was disconnected
            if num == Protocol.NetworkErrorCodes.DISCONNECTED:
                print msg
                self.shut_down_server()
    

    it get into the second if and print 'ERROR - Could not receive a message: timed out.'

    How do I fix this properly?

    P.S

    I am using Linux