为了账号安全,请及时绑定邮箱和手机立即绑定

为什么这些Python发送/接收套接字函数在缓慢调用时可以工作,但在连续快速调用时会失败?

为什么这些Python发送/接收套接字函数在缓慢调用时可以工作,但在连续快速调用时会失败?

九州编程 2023-06-27 17:22:24
我有一个客户端和一个服务器,服务器需要向客户端发送许多文本文件。发送文件函数接收套接字和要发送的文件的路径:CHUNKSIZE = 1_000_000def send_file(sock, filepath):    with open(filepath, 'rb') as f:        sock.sendall(f'{os.path.getsize(filepath)}'.encode() + b'\r\n')        # Send the file in chunks so large files can be handled.        while True:            data = f.read(CHUNKSIZE)            if not data:                break            sock.send(data)接收文件函数接收客户端套接字和保存传入文件的路径:CHUNKSIZE = 1_000_000def receive_file(sock, filepath):    with sock.makefile('rb') as file_socket:        length = int(file_socket.readline())        # Read the data in chunks so it can handle large files.        with open(filepath, 'wb') as f:            while length:                chunk = min(length, CHUNKSIZE)                data = file_socket.read(chunk)                if not data:                    break                f.write(data)                length -= len(data)    if length != 0:        print('Invalid download.')    else:        print('Done.')它的工作原理是将文件大小作为第一行发送,然后逐行发送文本文件。两者都是在客户端和服务端循环调用,从而将文件一一发送并保存。如果我设置断点并缓慢调用这些函数,效果会很好。但是如果我让程序不间断地运行,它在读取第二个文件的大小时会失败:  File "/home/stark/Work/test/networking.py", line 29, in receive_file    length = int(file_socket.readline())ValueError: invalid literal for int() with base 10: b'00,1851,-34,-58,782,-11.91,13.87,-99.55,1730,-16,-32,545,-12.12,19.70,-99.55,1564,-8,-10,177,-12.53,24.90,-99.55,1564,-8,-5,88,-12.53,25.99,-99.55,1564,-8,-3,43,-12.53,26.54,-99.55,0,60,0\r\n'显然,该线路正在接收更多的数据length = int(file_socket.readline())。我的问题:这是为什么?鉴于该行始终以尾随发送,难道该行不应该只读取大小吗\n?如何解决此问题以便可以连续发送多个文件?
查看完整描述

2 回答

?
冉冉说

TA贡献1877条经验 获得超1个赞

看起来您正在重复使用相同的连接,而发生的情况是您的file_socket缓冲意味着...您实际上已经recv从套接字中读取了更多内容,然后您会通过读取循环来思考。

即接收器从您的套接字消耗更多数据,并且下次您尝试readline()最终读取前一个文件的其余部分,直到其中包含的新行或下一个长度信息。

这也意味着您最初的问题实际上是您跳过了一段时间。下一个读取行的效果不是int您预期的,因此观察到了失败。

你可以说:

with sock.makefile('rb', buffering=0) as file_socket:

相反,强制文件访问不被缓冲。或者实际自行处理传入字节的接收、缓冲和解析(了解一个文件的结束位置和下一个文件的开始位置)(而不是像包装器和 那样的文件)readline


查看完整回答
反对 回复 2023-06-27
?
缥缈止盈

TA贡献2041条经验 获得超4个赞

您必须了解套接字通信是基于 TCP/IP 的,无论是同一台机器(在这种情况下使用环回)还是不同的机器都无关紧要。因此,您已经获得了一些在其之间建立连接的 IP 地址。更进一步,它涉及访问您的网络适配器,即与访问例如网络适配器相比需要相对较长的时间。内存。此外,适配器本身管理何时发送特定数据帧(较低的 ISO/OSI 层)。基本上,对于 TCP,需要 ACK,但在标准 PC 上,这通常不是某些工业实时以太网。

因此,在您的代码中,您有一个while True没有任何睡眠的循环,并且您不检查sock.send返回的内容。即使特定数据帧出现问题,您也会忽略它并尝试发送下一个。乍一看,似乎有些内容已被缓存,并且接收者收到了重新建立连接后刷新的内容。

因此,您应该做的第一件事是检查是否sock.send确实返回了发送的字节数。如果没有,我相信应该重新发送该帧。在这种情况下,我强烈建议的另一件事是考虑一些自定义协议(这通常在 OSI/ISO 堆栈的上下文中称为应用程序层)。例如,您可能有 4 种类型的帧:START、FILESIZE、DATA、END,分配唯一 ID 并以标识符开始每个帧。然后,START 将是空的,FILESIZE 将包含单个 uint16,DATA 将包含 {FILE NUMBER, LINE NUMBER, LINE_LENGTH, LINE},END 将是空的。然后,一旦您在客户端上获得了整个框架,您就可以安全地组合收到的信息。


查看完整回答
反对 回复 2023-06-27
  • 2 回答
  • 0 关注
  • 108 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信