【问题标题】:Python TCP Socket losing data in recv [acting weird]Python TCP Socket在recv中丢失数据[表现得很奇怪]
【发布时间】:2014-05-17 16:32:45
【问题描述】:

我在 Python 3.4 中编写了一个用于读取数据的简单套接字客户端

我遇到的问题是,当服务器发送少量数据(大约1000)字节时,它会完美读取它,但是当处理大量数据时(9500 字节)它只会给我一小块数据(比如1100-ish块)。我似乎无法弄清楚为什么在处理大量数据时它的行为如此不规律。我知道我的数据不大于ssize_t 最大32767

它在处理小数据时工作得很好,完全变成 180 并且在处理大量数据时表现不同。我知道这在 TCP 服务器中不是问题,因为我使用 PHP TCP 客户端对其进行了测试,并且在处理大量数据时它运行良好。

非常感谢任何帮助。

import socket
import json

# Written in Python 3.4.

class SocketClient:

    def __init__(self, host, port, format, timeout = None):
        # Constructor
        self.host = host
        self.port = port
        self.format = format
        self.timeout = timeout

        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def send(self, firstname, lastname, parameters = [], format = 'json'):
        if self.socket is not None:
            self.socket.connect((self.host, self.port))

            data = {}
            data['firstname'] = firstname
            data['lastname'] = lastname
            data['parameters'] = parameters
            data['format'] = format

            self.socket.send(bytes(json.dumps(data), "utf-8"))

            result = self.socket.recv(32767)
            result = result.decode()

            return result

    def shutdown(self):
        if socket is not None:
            self.socket.shutdown(socket.SHUT_RDWR)
            self.socket.close()


if __name__ == __main__:
    client = SocketClient("127.0.0.1", 8080, 'json')
    response = client.send('foo', 'bar', ['foobar'])
    print(response)
    client.shutdown()

【问题讨论】:

    标签: python sockets tcp


    【解决方案1】:

    TCP 是一种流协议。数据以字节的垃圾形式传递,其中长度由许多因素决定。一是内部缓冲区限制为几千字节。您永远无法一次读取 32767 个字节。 recv 的唯一保证是,您至少获得 1 个字节,最多获得您所说的字节数。您的代码必须处理这个问题,这意味着,您必须进行多次recv 调用,直到获得所需的字节数。这意味着另一方面,没有消息结束指示符或长度编码的协议被严重破坏。在您的情况下:您必须解析 json 字节流,直到发送有效的 json 表达式。但是1245.6 呢?收到112 或...后是否完成? 要修复您的协议,只需将一些长度信息与您的 json 数据一起发送。

    对于发送,您应该使用sendall 而不是send

    【讨论】:

      【解决方案2】:

      你可以使用recv_into(buffer[, nbytes[, flags]])方法:

      def readReliably(s,n):
          buf = bytearray(n)
          view = memoryview(buf)
          sz = 0
          while sz < n:
              k = s.recv_into(view[sz:],n-sz)
              sz += k
          # print 'readReliably()',sz
          return sz,buf
      
      def writeReliably(s,buf,n):
          sz = 0
          while sz < n:
              k = s.send(buf[sz:],n-sz)
              sz += k
          # obj = s.makefile(mode='w')
          # obj.flush()
          # print 'writeReliably()',sz
          return sz
      

      查看完整示例:https://stackoverflow.com/a/55446223/966789

      while True:
        sk,skfrom = s.accept()
        sz,buf = io.readReliably(sk,4)
        a = struct.unpack("4B",buf)
        print repr(a)
        # ...
        io.writeReliably(sk,struct.pack("4B",*[0x01,0x02,0x03,0x04]))
      

      【讨论】:

        【解决方案3】:

        这就是 recv 在不止一种语言中的工作方式...https://docs.python.org/3.4/library/socket.html#socket.socket.recv

        【讨论】:

        • 我明白……但是当你给一个大缓冲区时,为什么它在处理不同大小的数据时会有如此不同的行为呢?
        • 你没有给它一个大的缓冲区。您只需要求系统最多读取那么多内容。
        • 我告诉它最多读取32767,但要读取的实际数据小于32767。它在10000 附近,但它没有完全阅读它,它被切断了。当我在2000 附近读取数据时,它可以工作。我已经进行了几次测试并确认它不是实际的 TCP 服务器问题。它只是在 Python 中导致它的行为如此怪异。
        猜你喜欢
        • 1970-01-01
        • 2020-03-17
        • 2020-07-05
        • 2013-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-04
        相关资源
        最近更新 更多