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
для отправки и получения целых сообщений, и у них не будет проблем с разбиением пакетов или объединены на сетевом уровне.