Search code examples
pythonpython-2.7socketsserversocket

Terminating client connection to server using keyboard shortcut in python


I am trying to modify a server and client chat script implemented in python. One of the requirement is that the client exits when the user types CTRL-D. My question is how do I read that the user typed (ctrl-D) and implement it within this code. Should I just close the socket like c_socket.close() without any message back to the server that I am exiting?

Thanks!

# telnet program example
import socket, select, string, sys
import readline 
def prompt() :
    sys.stdout.write('<You> ')
    sys.stdout.flush()

#main function
if __name__ == "__main__":

    if(len(sys.argv) < 3) :
        print 'Usage : python MClient hostname port'
        sys.exit()

    host = sys.argv[1]
    port = int(sys.argv[2])

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(2)

    # connect to remote host
    try :
        s.connect((host, port))
    except :
        print 'Unable to connect'
        sys.exit()

    print 'Connected to remote host. Start sending messages'
    prompt()

    while 1:
        socket_list = [sys.stdin, s]

        # Get the list sockets which are readable
        read_sockets, write_sockets, error_sockets = select.select(socket_list , [], [])

        for sock in read_sockets:
            #incoming message from remote server
            if sock == s:
                data = sock.recv(4096)
                if not data :
                    print '\nDisconnected from chat server'
                    sys.exit()
                else :
                    #print data
                    sys.stdout.write(data)
                    prompt()

            #user entered a message
            else :
                msg = sys.stdin.readline()
                s.send(msg)
                prompt()

Solution

  • Last thing first - whether you need to send something to the server before closing the socket or not depends purely on your protocol. Given the simplistic nature of the presented client code, I'd guess that closing of the socket should be enough (and the server should treat unannounced disconnects anyway as one shouldn't consider network I/O as persistent).

    Second, CTRL+D will cause the returned message from sys.stdin.readline() to return as empty so you can test against that, e.g.:

    msg = sys.stdin.readline()
    if msg:
        s.send(msg)
        prompt()
    else:
        s.close()
        sys.exit()
    

    If you really need to send something to the server (again, depends on the protocol) you can use socket's shutdown() method before calling close().

    However, keep in mind that the code presented here doesn't account for pressing the CTRL+D while reading from the socket (i.e. receiving data) so if there is a particularly long data stream coming in your CTRL+D won't be registered. You can solve this by checking the user input (and writing it to buffer for later sending) during the retrieval procedure, or you can just place your receiving code in a separate thread and leave the main thread just for user input.

    You can then use the atexit module to cleanly exit from your client at any time.