3 回答
TA贡献1842条经验 获得超21个赞
TCP / IP是基于流的协议,而不是基于消息的协议。不能保证send()一个对等方的每个呼叫都会导致另一对等方的单个recv()呼叫接收到发送的确切数据recv(),由于数据包分段,它可能会接收到数据块,并分成多个呼叫。
您需要在TCP之上定义自己的基于消息的协议,以区分消息边界。然后,要阅读消息,请继续呼叫recv()直到您阅读了整个消息或发生错误为止。
发送消息的一种简单方法是为每个消息加上前缀。然后要读取一条消息,您首先要读取长度,然后读取那么多字节。您可以按照以下方式进行操作:
def send_msg(sock, msg):
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock):
# Read message length and unpack it into an integer
raw_msglen = recvall(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('>I', raw_msglen)[0]
# Read the message data
return recvall(sock, msglen)
def recvall(sock, n):
# Helper function to recv n bytes or return None if EOF is hit
data = b''
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data += packet
return data
然后,您可以使用send_msg和recv_msg函数来发送和接收整个消息,并且它们不会在网络级别拆分或合并数据包时带来任何问题。
TA贡献1890条经验 获得超9个赞
您可以将其用作: data = recvall(sock)
def recvall(sock):
BUFF_SIZE = 4096 # 4 KiB
data = b''
while True:
part = sock.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
# either 0 or end of data
break
return data
TA贡献1893条经验 获得超10个赞
可以接受的答案很好,但是对于大文件来说这确实会很慢-string是一个不可变的类,这意味着每次使用+符号时都会创建更多对象,将其list用作堆栈结构会更有效。
这应该更好地工作
while True:
chunk = s.recv(10000)
if not chunk:
break
fragments.append(chunk)
print "".join(fragments)
添加回答
举报