Python套接字,从服务器请求文件然后等待接收它

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python套接字,从服务器请求文件然后等待接收它相关的知识,希望对你有一定的参考价值。

我试图从我的客户端使用特定的文件名向我的服务器发送一个字符串,然后将该文件发送到客户端。出于某种原因,即使收到所有文件后它也会挂起。它挂在:

m = s.recv(1024)

client.朋友

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.1.2", 54321))
s.send(b"File:test.txt")
f = open("newfile.txt", "wb")
data = None
while True:
    m = s.recv(1024)
    data = m
    if m:
        while m:
            m = s.recv(1024)
            data += m
        else:
            break
f.write(data)
f.close()
print("Done receiving")

server.朋友

import socket
import os

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 54321))

while True:
    client_input = c.recv(1024)
    command = client_input.split(":")[0]
    if command == "File":
        command_parameter = client_input.split(":")[1]
        f = open(command_parameter, "rb")
        l = os.path.getsize(command_parameter)
        m = f.read(l)
        c.sendall(m)
        f.close()
答案

TLDR

recv阻塞的原因是因为在发送文件数据后套接字连接没有关闭。实现当前无法知道通信何时结束,这导致两个远程进程之间的死锁。要避免这种情况,请关闭服务器中的套接字连接,这将在客户端生成文件结束事件(即recv返回零长度字符串)。

更多洞察力

每当您设计任何两个进程相互通信的软件时,您必须定义一个消除通信歧义的协议,以便两个对等方始终确切知道它们处于哪种状态。通常,这涉及使用通信的语法来帮助指导数据的解释。

目前,您的实施存在一些问题:它没有定义足够的协议来解决潜在的歧义。当你考虑到在一个对等体中对send的每次调用不一定对应于另一个对recv的一次调用这一事实时,这就变得很明显。也就是说,对sendrecv的调用不一定是一对一的。考虑在严重拥塞的网络上将文件名发送到服务器:当第一次调用recv返回时,可能只有一半的文件名进入服务器。服务器无法(当前)知道它是否已完成接收文件名。客户端也是如此:客户端如何知道文件何时完成?

为了解决这个问题,我们可以在协议中引入一些语法,并在服务器中引入一些逻辑,以确保在继续之前获取完整的文件名。一个简单的解决方案是使用EOL字符,即 来表示客户端消息的结束。现在,99.99%的时间在测试中只需要一次调用recv即可读入。但是你必须预测可能需要多次调用recv的情况。显然,这可以使用循环来实现。

客户端对于此演示更简单。如果在发送文件之后通信结束,则该事件可用于表示数据流的结束。当服务器在其末端关闭连接时会发生这种情况。

如果我们要将实现扩展到允许多个背靠背文件的请求,那么我们必须在协议中引入一些机制来区分一个文件的结尾和下一个文件的开头。请注意,这也意味着服务器需要潜在地缓冲它在先前迭代中读取的额外字节,以防有重叠。流实现通常适用于这些类型的事物。

以上是关于Python套接字,从服务器请求文件然后等待接收它的主要内容,如果未能解决你的问题,请参考以下文章

Python 网络编程

套接字及通信

Python之socket详解

Python 核心编程(第二版)——网络编程

Python网络编程

如何将数据从 Python 异步套接字服务器发送到子进程?