0

I have a python script where the server receives a large file. It works well but I have a problem to stop listening for more data. The socket is blocked because after the last transmission of data (e.g. 14 bytes), the socket tries in a loop to receive more data. This is the reason why it hangs at this position.

 while True:
        try:
            (clientsocket, address) = serversocket.accept()    
            print('Got connection from', address)
            data = clientsocket.recv(4096)
            print("REVEIVING DATA")
            print("data=%s",len(data))
            if not data:
                print("NEVER REACHED")
                break

One workaround might be:

if len(data) < buffersize:
        break

to get out of the loop. The problem is if the last package has the same size as buffersize. What is the best way to prevent clientsocket.recv blocking the script if there is no more data? Do I have to transmit the file size before?

Edit: I though about using a non-blocking socket. When I try this by using the command clientsocket.setblocking(0), the recv method is not blocked. But I get the problem that the data is read until there is not more data (e.g. 1024 in 1st iteration, 1024 bytes in 2nd iteration and the last 14 bytes in third iteration). Then it raises an exception which could be catched to close the written file. This works. But I have a problem if I start the server, connect a client and send data. If the server does not receive bytes during the first iteration, it raises an exception. So I cannot guarantee that there are data for the first call of recv. Furthermore the statement if not data is never called. Do you know how I could get it called?

JavaForAndroid
  • 1,111
  • 2
  • 20
  • 42

1 Answers1

0

If one wants recv not to block one either need to make sure that the socket is set non-blocking, or make sure that there are actual data to read. The latter can be done if one knows up-front how much data will be expected or if there is some kind of indicator in the data which signals the end of the data or message.

Knowledge about the size can be provided implicitly due to only transferring fixed-size data or it can be provided more explicitly by prefixing the content with a size or prefixing it with some kind of type which then has associated size information in the code.

An "end of data" indicator is implicitly provided by the TCP peer shutting down the connection, in which case recv will return with success but only b'' read. This can be easily checked. And "end of message" indicator (like end of line) is more complex - here one need to scan all received data for this indicator and also maybe deal with multiple messages read at once, reading only parts of the message etc.

What is best depends on the requirements of the specific application and the used application protocol. In practice all of these methods are used. The easiest is likely just use TCP shutdown as end of data but due to costs of TCP connection setup and tear down this does not scale well if multiple messages need to be transferred.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • I tried the approach. But I am struggling with the recv statement. I tried to use a non-blocking socket. It runs. If there is no data during the first iteration, it would raise an exception. In my idea this exception should be used to notice the end of a file. But that would only work if there is data at the first run of the loop. Furthermore the if not data: is never called. Is there an option to get the return value of recv if there is no message? Or would it always throw an exception? I added the question with additional info. – JavaForAndroid Feb 09 '21 at 20:01
  • @JavaForAndroid: It is normal that `recv` will throw an exception if no data are available. But one should catch this exception - see [What does Python's socket.recv() return for non-blocking sockets if no data is received until a timeout occurs?](https://stackoverflow.com/questions/16745409/). And one should better also call `recv` only if a previous [select](https://docs.python.org/3/library/select.html) indicated that data will be available. – Steffen Ullrich Feb 09 '21 at 20:25