Megalegacy Megalegacy - 3 months ago 19
Python Question

Sockets Python 3.5: Socket server hangs forever on file recieve

I'm trying to write a Python program that can browse directories and grab files w/ sockets if the client connects to the server. The browsing part works fine, it prints out all directories of the client.
Here's a part of the code:

with clientsocket:
print('Connected to: ', addr)
while True:
m = input("Command > ")

clientsocket.send(m.encode('utf-8'))
data = clientsocket.recv(10000)

if m == "exit":
clientsocket.close()
if m.split()[0] == 'get':
inp = input("Filename > ")
while True:
rbuf = clientsocket.recv(8192)
if not rbuf:
break

d = open(inp, "ab")
d.write(rbuf)
d.close()


elif data.decode('utf-8').split()[0] == "LIST":
print(data.decode('utf-8'))
if not data:
break


However, the problem lies in here:

if m.split()[0] == 'get':
inp = input("Filename > ")
while True:
rbuf = clientsocket.recv(8192)
if not rbuf:
break


It seems to be stuck in an infinite loop. What's more interesting is that the file I'm trying to recieve is 88.3kb, but what the file returns is 87kb while it's in the loop, which is very close...

I tried receiving a python script at one time as well (without the loop) and it works fine.

Here's some of the client code:

while True:
msg = s.recv(1024).decode('utf-8')


if msg.split()[0] == "list":
dirs = os.listdir(msg.split()[1])
string = ''
for dira in dirs:
string += "LIST " + dira + "\n"
s.send(string.encode('utf-8'))
elif msg == "exit":
break
else:
#bit that sends the file
with open(msg.split()[1], 'rb') as r:
s.sendall(r.read())


So my question is, why is it getting stuck in an infinite loop if I have it set up to close when there is no data, and how can I fix this?

I'm sort of new to network programming in general, so forgive me if I miss something obvious.

Thanks!

Answer

I think I know what's the problem, but I may be wrong. It happened to me several times, that the entire message is not received in one recv call, even if I specify the correct length. However, you don't reach the end of stream, so your program keeps waiting for remaining of 8192 bytes which never arrives.

Try this:
Sending file:

#bit that sends the file
with open(msg.split()[1], 'rb') as r:
   data = r.read()
   # check data length in bytes and send it to client
   data_length = len(data)
   s.send(data_length.to_bytes(4, 'big'))
   s.send(data)
s.shutdown(socket.SHUT_RDWR)
s.close()

Receiving the file:

# check expected message length
remaining = int.from_bytes(clientsocket.recv(4), 'big')
d = open(inp, "wb")
while remaining:
    # until there are bytes left...
    # fetch remaining bytes or 4094 (whatever smaller)
    rbuf = clientsocket.recv(min(remaining, 4096))
    remaining -= len(rbuf)
    # write to file
    d.write(rbuf)
d.close()