3 回答

TA貢獻(xiàn)1842條經(jīng)驗(yàn) 獲得超22個(gè)贊
TCP / IP是基于流的協(xié)議,而不是基于消息的協(xié)議。不能保證send()一個(gè)對(duì)等方的每個(gè)呼叫都會(huì)導(dǎo)致另一對(duì)等方的單個(gè)recv()呼叫接收到發(fā)送的確切數(shù)據(jù)recv(),由于數(shù)據(jù)包分段,它可能會(huì)接收到數(shù)據(jù)塊,并分成多個(gè)呼叫。
您需要在TCP之上定義自己的基于消息的協(xié)議,以區(qū)分消息邊界。然后,要閱讀消息,請(qǐng)繼續(xù)呼叫recv()直到您閱讀了整個(gè)消息或發(fā)生錯(cuò)誤為止。
發(fā)送消息的一種簡(jiǎn)單方法是為每個(gè)消息加上前綴。然后要讀取一條消息,您首先要讀取長(zhǎng)度,然后讀取那么多字節(jié)。您可以按照以下方式進(jìn)行操作:
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函數(shù)來(lái)發(fā)送和接收整個(gè)消息,并且它們不會(huì)在網(wǎng)絡(luò)級(jí)別拆分或合并數(shù)據(jù)包時(shí)帶來(lái)任何問題。

TA貢獻(xiàn)1890條經(jīng)驗(yàn) 獲得超9個(gè)贊
您可以將其用作: 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貢獻(xiàn)1893條經(jīng)驗(yàn) 獲得超10個(gè)贊
可以接受的答案很好,但是對(duì)于大文件來(lái)說這確實(shí)會(huì)很慢-string是一個(gè)不可變的類,這意味著每次使用+符號(hào)時(shí)都會(huì)創(chuàng)建更多對(duì)象,將其list用作堆棧結(jié)構(gòu)會(huì)更有效。
這應(yīng)該更好地工作
while True:
chunk = s.recv(10000)
if not chunk:
break
fragments.append(chunk)
print "".join(fragments)
添加回答
舉報(bào)