我正在尝试编写一个Python程序,如果客户端连接到服务器,它可以浏览目录并获取带有套接字的文件。浏览部分工作正常,它打印出客户端的所有目录。 这是代码的一部分:
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
然而,问题出在这里:
if m.split()[0] == 'get':
inp = input("Filename > ")
while True:
rbuf = clientsocket.recv(8192)
if not rbuf:
break
似乎陷入无限循环。更有趣的是,我试图接收的文件是88.3kb,但文件返回的是87kb而它在循环中,这非常接近......
我也尝试过一次接收一个python脚本(没有循环),它运行正常。
以下是一些客户端代码:
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())
所以我的问题是,如果我在没有数据时将其设置为关闭,为什么它会陷入无限循环?我该如何解决这个问题呢?
我对网络编程一般都是新手,如果我错过了一些明显的东西,请原谅我。
谢谢!
答案 0 :(得分:1)
我想我知道问题是什么,但我可能错了。它发生在我身上几次,即使我指定了正确的长度,也不会在一次recv
调用中收到整条消息。但是,您没有到达流的末尾,因此您的程序一直在等待剩余的8192个字节,这些字节永远不会到达。
试试这个:
发送文件:
#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()
收到文件:
# 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()
答案 1 :(得分:1)
您的代码存在一些问题。
首先:
clientsocket.send(m.encode('utf-8'))
data = clientsocket.recv(10000)
这会导致在发出data
语句时将文件部分加载到get
变量。这就是为什么你没有获得完整档案的原因。
现在这个:
while True:
rbuf = clientsocket.recv(8192)
if not rbuf:
break
...
您确实加载了完整文件,但客户端从不关闭连接(在发送文件后它会转到s.recv()
),因此永远不会满足if
语句。因此,在下载文件后,此循环在clientsocket.recv(8192)
部分被阻止。
所以问题是你必须以某种方式通知下载者你已经发送了所有数据,即使连接仍然是打开的。有几种方法可以做到这一点:
您计算文件的大小并将其作为前几个字节发送。例如,假设文件的内容为ala ma kota
。这些是11个字节,因此您发送\x11ala ma kota
。现在接收器知道第一个字节是大小,它会解释它。当然,一个字节标题不是很多(你只能发送最多256个字节的文件)所以通常你需要4个字节。所以现在你的客户端和服务器之间的协议是:前4个字节是文件的大小。因此,我们的初始文件将以\x0\x0\x0\x11ala ma kota
发送。此解决方案的缺点是您必须在发送内容之前知道内容的大小。
您标记了流的结尾。所以你选择一个特定的角色,比如X
,你就读到了这个版本,直到找到X
。如果你这样做,你知道对方发送了它所拥有的一切。缺点是,如果内容中有X
,则必须将其转义,即需要额外的内容处理(以及另一方的解释)。