Python中socket接收数据的问题如何解决?
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
我一直循环接收数据,理论上会接收到 3 次及 3 次以上空数据就会退出接收数据,但是,实际发现只要数据量有点大,就会导致循环退出,然后会重新再接收数据。下面是数据打印的结果 10240 第 56 次读取数据 10240 第 57 次读取数据 8656 第 58 次读取数据 第 1 次获取到空数据,继续尝试中....... 第 59 次读取数据 第 2 次获取到空数据,继续尝试中....... 第 60 次读取数据 第 3 次获取到空数据,继续尝试中....... 第 61 次读取数据 数据总长度 582096 帧为:127 Unknown opcode %#x.15 解析数据帧暂时不用的状态 第 1 次读取数据--------------------------------->这儿明显重新开始接收数据了!!! 10240 第 2 次读取数据 10240
求解各位大神
Python中socket接收数据的问题如何解决?
这排版,辣眼睛。
在Python里用socket收数据,最常见的问题就是不知道数据什么时候收完。TCP是流式协议,发过来的数据可能被拆成多个包,也可能粘在一起。你得自己处理消息边界。
最常用的方法就两种:
- 固定长度法:每条消息都固定长度,比如总是发1024字节,不够就补零。
- 分隔符法:用特殊字符(比如
\n)标记消息结束。 - 长度前缀法(推荐):先发消息长度,再发实际数据。
给你个长度前缀法的例子,这是最靠谱的方式:
import socket
import struct
def send_msg(sock, msg):
# 先打包消息长度(4字节无符号整数)
msg_len = len(msg)
sock.sendall(struct.pack('>I', msg_len))
# 再发实际数据
sock.sendall(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)
def recv_all(sock, n):
data = bytearray()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data.extend(packet)
return bytes(data)
# 使用示例
with socket.socket() as s:
s.connect(('localhost', 12345))
send_msg(s, b'Hello World')
received = recv_msg(s)
print(received)
关键在recv_all函数,它确保收够指定字节数。struct.pack('>I', msg_len)把长度打包成网络字节序的4字节,这样接收方就知道该收多少数据。
另一种简单情况是用分隔符,比如\n:
def recv_until(sock, delimiter=b'\n'):
data = b''
while True:
chunk = sock.recv(1)
if not chunk:
break
data += chunk
if data.endswith(delimiter):
break
return data
用哪种方法看你的协议设计,但别指望一次recv()就能收完所有数据。
总结:自己处理消息边界,别依赖单次recv。
建议好好排下版再问
所以源码都没贴全是让大家脑补帮你 debug 吗?
请问你 epollHandle.modify 有没有把 socket 给 close 掉?没有的话,对端会一直发空字符串过来,告诉你关闭 socket 的。但这一部分没有贴出来,所以我怀疑你 modify 方法没有关闭 socket,导致对端一直发送空字符串,让你一直以为有数据接受。
c 的 epoll 我记得也是发送空字符串告诉你 socket 关闭的,python 和 c 在系统 api 上差异不大
这块我处理了的

