【问题标题】:Python file transfer (tcp socket), problem with slow networkPython文件传输(tcp套接字),网络慢的问题
【发布时间】:2024-01-09 03:29:01
【问题描述】:

我使用 Tor 和 socks 设置了一个安全套接字,但是在发送大量数据时遇到了问题

发件人:

socket.send(message.encode())

接收者:

chunks = []

while 1:
    part = connection.recv(4096)
    chunks.append(part.decode())

    if len(part) < 4096:
        break

response = "".join(chunks)

由于网络速度在循环中不一致,我并不总是填充 4096b 缓冲区,因此循环中断并且我没有收到完整的数据。

降低缓冲区大小似乎不是一种选择,因为“数据包”大小有时可能低至 20b

【问题讨论】:

    标签: python python-3.x tcp proxy file-transfer


    【解决方案1】:

    TCP 可以将您的包裹数据拆分成任意数量的片段。所以你应该从不依赖套接字的另一端接收到的数据包的大小。您必须发明另一种机制来检测消息结束/文件结束。

    如果你打算只发送一个 blob 并关闭套接字,那么在服务器端你只需要读取直到你得到 False 值:

    while True:
        data = sock.recv(1024)
        if data:
            print(data)
            # continue 
        else:
            sock.close()
            break
    

    如果您要发送多条消息,您必须决定它们之间的分隔符是什么。对于文本协议,使用 lineending 是个好主意。然后,您可以享受 Twisted LineReceiver 协议和其他协议的强大功能。

    如果您使用的是二进制协议,通常的做法是在每条消息前加上大小字节/字/双字。

    【讨论】:

      【解决方案2】:

      尝试使用结构首先将传入数据的长度传递给接收者,“import struct”。这样接收端就知道要接收多少数据。在这个示例中,字节是通过套接字发送的,这里的示例是我从我的 github 上传的 github.com/nsk89/netcrypt 中借来的以供参考,并从发送函数中删除了加密步骤以及发送序列化字典。

      编辑 我还应该澄清一下,当您通过套接字发送数据时,尤其是当您发送多条消息时,它们都作为一条长消息位于流中。并非每条消息的长度都是 4096 字节。如果一个长度为 2048,下一个为 4096,并且您在缓冲区中收到 4096,您将收到第一条消息加上下一条消息的一半,或者完全挂起等待更多不存在的数据。

      data_to_send = struct.pack('>I', len(data_to_send)) + data_to_send # pack the length of data in the first four bytes of data stream, >I indicates internet byte order
      
          socket_object.sendall(data_to_send)  # transport data
      
      
      
      def recv_message(socket_object):
          raw_msg_length = recv_all(socket_object, 4)  # receive first 4 bytes of data in stream
          if not raw_msg_length:
              return None
      
          # unpack first 4 bytes using network byte order to retrieve incoming message length
          msg_length = struct.unpack('>I', raw_msg_length)[0]
      
          return recv_all(socket_object, msg_length)  # recv rest of stream up to message length
      
      def recv_all(socket_object, num_bytes):
          data = b''
          while len(data) < num_bytes:  # while amount of data recv is less than message length passed
              packet = socket_object.recv(num_bytes - len(data))  # recv remaining bytes/message
              if not packet:
                  return None
              data += packet
          return data
      

      【讨论】:

        【解决方案3】:

        顺便说一句,在将它们组合成一个块之前不需要解码每个部分,将所有部分组合成一个块然后解码该块。

        对于您的情况,更好的方法是使用 2 个步骤。

        Step1:发送者发送消息的大小,接收者取这个大小准备接收消息。

        Step2:发送方发送消息,接收方根据需要合并数据。

        发件人

        # Step 1
        socket.send( str(len(message.encode())).encode() ) 
        # Step 2
        socket.send(message.encode("utf-8"))   
        

        接收者

        # Step 1
        message_size = connection.recv(1024) 
        print("Will receive message size:",message_size.decode())
        
        # Step 2
        recevied_size  = 0 
        recevied_data = b''
          while recevied_size < int(message_size.decode()):
              part = connection.recv(1024)
              recevied_size += len(part)
              recevied_data += part
          else:
              print(recevied_data.decode("utf-8", "ignore"))
              print("message receive done ....",recevied_size)
        

        【讨论】:

          最近更新 更多