0

First off, I've got the following code that... works. Apparently.

while not self.socket_connected:
    try:
        client_socket.connect((self.hostname, self.port))
        self.socket_connected = True
    except:
        sleep(0.5)
        pass

while self.socket_connected:
    message = client_socket.recv(4096)
    if(message == b''):
        client_socket.close()
        self.socket_connected = False
        break

    #...do stuff

I say "apparently" because I'm reading conflicting sources about how one ought to implement sockets in Python.

Firstly, you've got information as here and here that would have you believe an empty buffer is a disconnected socket. That must've been what I read first (the code above is a few months old at this point, and my first serious attempt at sockets in Python).

However, there's also this post that seems a little better informed. That is, if the buffer is empty, it just means you've read everything available for now. Kind of like how I understand TCP to work in the first place. And maybe I missed it, but is that even mentioned in the docs?

Anyway... what I realized about my code is that, every time the buffer is empty, I drop the client-side socket and reconnect to read new information. That's obviously not ideal, and I'd like to change it.

In C, if recv returns zero, the buffer is empty. If it returns <0, something's gone wrong and you can destroy the file descriptor and attempt to reestablish the connection. How is one supposed to do the same in Python?

EDIT: Just as a bit more context - I've got the first five bytes of the messages being received here encoded to the size of the overall message, so I'll be able to test for 'done-ness' internally, provided that I can distinguish between an empty buffer and a dropped socket.

EDIT 2: What I'm asking specifically is how to check Python sockets for both an empty buffer as well as a dropped connection. Both should be handled differently, of course, and I need to make sure I'm getting the full message by possibly doing multiple recv() calls.

pdm
  • 1,027
  • 1
  • 9
  • 24

1 Answers1

0

By default socket.recv is a blocking call, it'll suspend the thread until there is something it has received in the buffer, then it'll return the whole buffer.

When a socket is disconnected the buffer will become b'' not empty, so it returns b''.

Non blocking sockets that have no data when you call .recv will return a socket exception.

So to answer what I believe the question is, by default, socket.recv will return b'' when the client disconnects.

edit: To see if a socket is empty, you could disable blocking, and then catch the exception that would be thrown by calling recv when the buffer is empty.

Alternatively using the select module with sockets to sort your sockets into 3 lists, ready to read, ready to write, and sockets with exceptions.

https://docs.python.org/3/library/select.html#select.select

Savagery
  • 56
  • 4
  • So test for `b''` for a disconnected socket, and `msg == None` or something for an empty buffer? I'm trying to be able to test for both so that I can account for partial messages as well as dropped sockets. – pdm Jun 10 '18 at 23:19