socket closing problem

Discussion in 'Python' started by flupke, Jul 8, 2004.

  1. flupke

    flupke Guest

    Hi,

    I have a gui (made in wxPython) that enables a user to connect to a server
    and issue some commands. The problem occurs when i try to disconnect the
    client. It exits but it doesn't return to the prompt. I have to push
    Ctrl-C in order to have it exit completely. The GUI is closed though.

    This is a piece of code from the main class that connects to the server
    and starts a thread that handles the connection:
    ======================= snippet =======================
    Create a socket and start a thread to handle the connection:
    #create an INET, STREAMing socket
    self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #now connect to the CheckServer
    try:
    self.s.connect((host, int(data)))
    except socket.error, msg:
    sys.stderr.write('connect failed: ' + repr(msg) + '\n')
    sys.exit(1)

    self.connection = client_connection(self.s, self)
    self.connection.start()
    ======================= snippet =======================

    client_connection is the thread that handles the connection.
    Next, the client_connection class

    ======================= snippet =======================
    BUF_SIZE = 1024

    class client_connection(threading.Thread):
    def __init__(self,client_socket,parent):
    self.client_socket = client_socket
    self.parent = parent
    threading.Thread.__init__(self)

    def run(self):
    done = 0
    try:
    while not done:
    print "ready to receive data"
    try:
    data = self.client_socket.recv(BUF_SIZE)
    except socket.error, msg:
    print "Error receiving data"
    break
    if not data:
    print "all data received"
    break

    print "receiving data"
    sys.stdout.write(data)
    sys.stdout.flush()
    self.parent.handleCommand(data)
    finally:
    self.client_socket.close()
    print "Closing client socket"

    def message(self,msg):
    print "from client_connection", msg
    self.client_socket.sendall(msg+"\n")

    def close(self):
    #self.message("bye")
    done = 1
    self.client_socket.settimeout(0)
    self.client_socket.close()
    ======================= snippet =======================

    So when the user pushes the exit button, i try to call the close
    function of the client_connection class:
    ======================= snippet =======================
    def OnFileExit(self,e):
    self.connection.close()
    time.sleep(5)
    self.Close(true) # Close the frame.
    ======================= snippet =======================

    I thought that this would trigger the
    "data=self.client_socket.recv(BUF_SIZE)"
    from the client_connection class in such a way that it would produce an
    exception or return empty data so i could close the thread gracefuly.
    Apparently this doesn't happen.

    When the server initiates the closing of the socket, then all happens fine.
    How can i solve this & what am i doing wrong?

    Thanks,
    Benedict
    flupke, Jul 8, 2004
    #1
    1. Advertising

  2. flupke

    Gandalf Guest


    > try:
    > data = self.client_socket.recv(BUF_SIZE)
    > except socket.error, msg:
    > print "Error receiving data"
    > break
    > if not data:
    > print "all data received"
    > break


    ....

    >
    > I thought that this would trigger the
    > "data=self.client_socket.recv(BUF_SIZE)"
    > from the client_connection class in such a way that it would produce an
    > exception or return empty data so i could close the thread gracefuly.
    > Apparently this doesn't happen.
    >
    > When the server initiates the closing of the socket, then all happens
    > fine.
    > How can i solve this & what am i doing wrong?


    Well, here is what you need to know:

    1. First you should call select.select on the socket. Then you will know
    if there is data arrived from the server.
    2. If so then you should call client_socket.recv(). Please note that if
    you call recv() BEFORE any data has arrived, it will block your program.
    (Sockets are defaulting to blocking sockets.)
    3. Then you should examine the data received. There are two possibilities:

    a.) Your 'data' is not empty -> process the data
    b.) Your 'data' is empty. -> it means that the server closed the
    connection.

    Conclusion: when select.select tells there is more data coming but you
    can only recv an empty string >>> it means that the socket has been
    closed from the other site. You need to call both select.select and recv
    to detect if the socket is closed or not. The same procedure works on
    the server side (with the client socket) too.

    Another note: you can call select.select on the server socket if you
    want to know when a client wants to connect to your server.

    Best,

    G
    Gandalf, Jul 8, 2004
    #2
    1. Advertising

  3. On Thu, 08 Jul 2004 07:10:30 GMT, flupke <> wrote:

    > So when the user pushes the exit button, i try to call the close
    > function of the client_connection class:
    >======================= snippet =======================
    > def OnFileExit(self,e):
    > self.connection.close()
    > time.sleep(5)
    > self.Close(true) # Close the frame.
    >======================= snippet =======================
    >
    > I thought that this would trigger the
    > "data=self.client_socket.recv(BUF_SIZE)"
    > from the client_connection class in such a way that it would produce an
    > exception or return empty data so i could close the thread gracefuly.
    > Apparently this doesn't happen.


    sockets are full-duplex, which means that there are two streams of data.
    One stream runs from your send-side to the receive-side of the server,
    and one stream runs in the other direction (from the send-side of the
    server to the receive-side of your connection).
    Other than the fact that both streams are connected to the same
    processes, both streams are independant.

    That means that actions you perform at the send-side are independant of
    actions you perform at the receive-side.
    Therefore, you cannot expect for the close() to have any effect at the
    recv().

    (unless the server co-operates of course, and closes its send-side as
    reaction to you closing its receive-side. Even then, you still have to
    be prepared to receive arbitrary amounts of data before you get EOF,
    because you don't know how much data is in the connection between the
    server and you).


    So the answer to your problem is not to rely on the server reacting to
    your close(), and organize you application such that you close both the
    send-side and the receive-side (instead of waiting for the EOF).


    Albert
    --
    Unlike popular belief, the .doc format is not an open publically available format.
    Albert Hofkamp, Jul 8, 2004
    #3
  4. flupke

    flupke Guest

    Thanks Gandalf & Albert,

    both your sollutions seem to be working.
    This is what i've tried but as to what is the most natural sollution,
    i'm not sure.

    1) using select.select on the socket (Gandalf)

    ========================= snippet =======================
    client _connection class:
    ...
    in_socket = [self.client_socket]
    try:
    while not done:
    print "ready to receive data"
    try:
    i, o, e = select.select(in_socket,[],[])
    for x_socket in i:
    data = x_socket.recv(BUF_SIZE)
    except socket.error, msg:
    print "Error receiving data"
    break
    ...

    main class:
    ...
    def OnFileExit(self,e):
    #self.s.close()
    #wait until the thread dies
    if ( self.s != None ):
    self.s.settimeout(0)
    self.connection.close()
    #self.s.close()
    time.sleep(5)
    self.Close(true) # Close the frame.
    ...
    ========================= snippet =======================

    Now, the exit closes the socket which triggers an exception, as
    expected. This also triggers a "clean" closing of the connection on the
    server.

    2) Albert said: "herefore, you cannot expect for the close() to have any
    effect at the recv()."
    So in order to close, i made sure that part of closing of the client is
    to first send a "bye" command to the server. This makes the server close
    the socket which then also triggers the exception.

    ========================= snippet =======================
    client _connection class:
    ...
    try:
    while not done:
    print "ready to receive data"
    try:
    data = self.client_socket.recv(BUF_SIZE)
    except socket.error, msg:
    print "Error receiving data"
    break
    ...
    def close(self):
    print "from client_connection close() "
    self.message("bye")
    done = 1
    self.client_socket.settimeout(0)
    self.client_socket.close()
    ========================= snippet =======================

    Now, there are 2 ways to solve my problem but i'm not sure which one is
    the nicest when you would aim for the most "logical" sollution.
    Any thoughts?

    Thanks,
    Benedict
    flupke, Jul 9, 2004
    #4
  5. flupke

    flupke Guest

    flupke wrote:

    > Thanks Gandalf & Albert,
    >
    > both your sollutions seem to be working.
    > This is what i've tried but as to what is the most natural sollution,
    > i'm not sure.
    >
    > 1) using select.select on the socket (Gandalf)
    >
    > ========================= snippet =======================
    > client _connection class:
    > ...
    > in_socket = [self.client_socket]
    > try:
    > while not done:
    > print "ready to receive data"
    > try:
    > i, o, e = select.select(in_socket,[],[])
    > for x_socket in i:
    > data = x_socket.recv(BUF_SIZE)
    > except socket.error, msg:
    > print "Error receiving data"
    > break
    > ...
    >
    > main class:
    > ...
    > def OnFileExit(self,e):
    > #self.s.close()
    > #wait until the thread dies
    > if ( self.s != None ):
    > self.s.settimeout(0)
    > self.connection.close()
    > #self.s.close()
    > time.sleep(5)
    > self.Close(true) # Close the frame.
    > ...
    > ========================= snippet =======================
    >
    > Now, the exit closes the socket which triggers an exception, as
    > expected. This also triggers a "clean" closing of the connection on the
    > server.
    >
    > 2) Albert said: "herefore, you cannot expect for the close() to have any
    > effect at the recv()."
    > So in order to close, i made sure that part of closing of the client is
    > to first send a "bye" command to the server. This makes the server close
    > the socket which then also triggers the exception.
    >
    > ========================= snippet =======================
    > client _connection class:
    > ...
    > try:
    > while not done:
    > print "ready to receive data"
    > try:
    > data = self.client_socket.recv(BUF_SIZE)
    > except socket.error, msg:
    > print "Error receiving data"
    > break
    > ...
    > def close(self):
    > print "from client_connection close() "
    > self.message("bye")
    > done = 1
    > self.client_socket.settimeout(0)
    > self.client_socket.close()
    > ========================= snippet =======================
    >
    > Now, there are 2 ways to solve my problem but i'm not sure which one is
    > the nicest when you would aim for the most "logical" sollution.
    > Any thoughts?
    >
    > Thanks,
    > Benedict


    Or i can combine the two. If the "bye" command doesn't trigger a close
    (for whatever reason, for instance lag) immediately, then the select
    could still handle the closing of the socket gracefully?

    ========================= snippet ==============================
    client _connection class:
    ...
    in_socket = [self.client_socket]
    try:
    while not done:
    print "ready to receive data"
    try:
    i, o, e = select.select(in_socket,[],[])
    for x_socket in i:
    data = x_socket.recv(BUF_SIZE)
    #data = self.client_socket.recv(BUF_SIZE)
    except socket.error, msg:
    print "Error receiving data"
    break
    ...
    def close(self):
    print "from client_connection close() "
    self.message("bye")
    done = 1
    self.client_socket.settimeout(0)
    self.client_socket.close()
    main class:
    ...
    def OnFileExit(self,e):
    #wait until the thread dies
    if ( self.s != None ):
    self.connection.close()
    time.sleep(5)
    self.Close(true) # Close the frame
    ...
    ========================= snippet ==============================

    So there seems to be 3 options. 1, 2 or both?
    What will it be?

    Benedict
    flupke, Jul 9, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Laszlo Nagy
    Replies:
    1
    Views:
    4,757
    Mark Wooding
    Jan 27, 2009
  2. Jean-Paul Calderone
    Replies:
    0
    Views:
    942
    Jean-Paul Calderone
    Jan 27, 2009
  3. Laszlo Nagy
    Replies:
    0
    Views:
    524
    Laszlo Nagy
    Feb 1, 2009
  4. Steve Holden
    Replies:
    0
    Views:
    643
    Steve Holden
    Feb 1, 2009
  5. Steve Holden
    Replies:
    1
    Views:
    698
Loading...

Share This Page