Python中socket接收数据的问题如何解决?

def recvMessage(self, sockHandle):#读取来自客户端的数据
        strings = b""
        getNullTime = 0
        client = self.dictSocketHandle[sockHandle]
        num = 1
        totalLen = 0
        while True:
            try:
                print("第"+str(num)+"次读取数据")
                data = client.recv(1024)  # 这儿如果没有拿够 1024 个字节的数据,那么会循环回来拿,但是,如果发现没有数据能拿到,socket 会自动中止,扔出一个异常,代码就结束执行,所以需要 try 一下。
                print(len(data))
                totalLen += len(data)
                if len(data) == 0:  # 通道断开或者 close 之后,就会一直收到空字符串。 而不是所谓的-1 或者报异常。这个跟 C 和 java 等其他语言很不一样。
                    self.epollHandle.modify(sockHandle, select.EPOLLHUP | select.EPOLLET)
                    break
                # print("本次接收到的数据........", data)
                strings = strings + data
            getNullTime = 0

        except IOError as err:
            if err.errno == 11:  # 发生 Resource temporarily unavailable 错误 错误码为 11,意为:数据尚未准备好,需要等待
                if getNullTime >= 3:
                    break
                else:
                    getNullTime = getNullTime + 1
                    print("第" + str(getNullTime) + "次获取到空数据,继续尝试中.......")
            else:
                print("读取数据,未知 IO 错误")
                self.epollHandle.modify(sockHandle, select.EPOLLHUP | select.EPOLLET)
                break
        except:
            print("未知错误")
            self.epollHandle.modify(sockHandle, select.EPOLLHUP | select.EPOLLET)
            break
        num += 1
    print("数据总长度", totalLen)
    return strings

为啥上面的代码 一旦我数据超过 1M,就会数据接收不全?然后该 socket 立马就会再去获取数据,导致数据再不同的两个 socket 的 recv 中。下面是获取的数据的过程,第 81 次读取数据,然后,又开始第 1 次读取数据了!!!

第 75 次读取数据
2896
第 76 次读取数据
4344
第 77 次读取数据
7240
第 78 次读取数据
第 1 次获取到空数据,继续尝试中.......
第 79 次读取数据
第 2 次获取到空数据,继续尝试中.......
第 80 次读取数据
第 3 次获取到空数据,继续尝试中.......
第 81 次读取数据
数据总长度 755856
帧为:204
Unknown opcode %#x.12
解析数据帧暂时不用的状态
第 1 次读取数据
10240
第 2 次读取数据
10240
第 3 次读取数据
10240
第 4 次读取数据
10240
第 5 次读取数据

Python中socket接收数据的问题如何解决?

5 回复

81 次读取数据,然后,又开始第 1 次读取数据了。。。我感觉你这个明显是第 2 个请求进来了。和第一个请求 81 次没有关联


在Python里用socket收数据,最常见的问题就是不知道数据什么时候收完。很多人用socket.recv(1024),但1024只是缓冲区大小,不是保证能收这么多。关键是要有协议来界定消息边界。

解决方案:

  1. 固定长度协议:发送方先发数据长度,接收方先收长度,再循环收数据直到收够。

    import struct
    import socket
    
    def send_msg(sock, msg):
        # 将消息长度打包为4字节的网络字节序整数
        msg = msg.encode('utf-8')
        msg_len = struct.pack('>I', len(msg))
        sock.sendall(msg_len + msg)
    
    def recv_msg(sock):
        # 先接收4字节的长度信息
        raw_len = recv_all(sock, 4)
        if not raw_len:
            return None
        msg_len = struct.unpack('>I', raw_len)[0]
        # 根据长度接收完整消息
        return recv_all(sock, msg_len).decode('utf-8')
    
    def recv_all(sock, n):
        data = b''
        while len(data) < n:
            packet = sock.recv(n - len(data))
            if not packet:
                return None
            data += packet
        return data
    
  2. 分隔符协议:用特定字符(如\n)标记消息结束。用recv直到收到分隔符。

    def recv_until(sock, delimiter=b'\n'):
        buffer = b''
        while True:
            chunk = sock.recv(1)
            if not chunk:
                break
            buffer += chunk
            if buffer.endswith(delimiter):
                return buffer[:-len(delimiter)]
        return buffer
    
  3. 直接处理流数据:对于HTTP这类自带Content-Length头的协议,先解析头部再收主体。

选哪种看你的应用场景。简单交互可以用分隔符,要精确控制就用固定长度。

总结:定好通信协议是解决socket收数据问题的关键。

我只发送了一个请求,是一张 1.8M 的图片,不可能有第二个请求进来

recv(1024, socket.MSG_WAITALL)

我的 socket 都是非阻塞模式的,貌似不能与 MSG_WAITALL 这个参数共用

回到顶部