Python TCP 服务器接收到单个 TCP 数据包拆分成多个数据包
Python TCP Server receives single TCP packet split into multiple packets
我在确定我托管的基于 Python 的 TCP 服务器上某些数据包拆分问题的原因时遇到了一些问题。
我的客户端连接到服务器后,它向服务器发送一个字符串,然后是 /n
。
数据包的 Wireshark 预览如下所示:
在这种情况下,您可以看到有效负载是"作为额外的特殊英国宝贝potatoes/n"
我的 TCP 服务器有以下接收代码:
def listenToClient(self, client, address):
size = 1024
while True:
try:
# Receive data from the client
data = client.recv(size)
print('CLIENT Data Received', client)
print(datetime.now())
print("Raw data received: ", data.hex())
Data: as the extra
except ConnectionAbortedError:
print(datetime.now())
print('CLIENT Disconnected:', client)
client.close()
return False
当收到上面的数据包时,打印如下:
CLIENT Data Received <socket.socket fd=428, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.0.16', 12345), raddr=('192.168.0.14', 47234)>
2020-11-14 22:48:20.087507
Raw data received: 617320746865206578747261
Data: as the extra
CLIENT Data Received <socket.socket fd=428, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.0.16', 12345), raddr=('192.168.0.14', 47234)>
2020-11-14 22:48:20.092495
Raw data received: 207370656369616c2062726974697368206261627920706f7461
Data: special british baby pota
CLIENT Data Received <socket.socket fd=428, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.0.16', 12345), raddr=('192.168.0.14', 47234)>
Raw data received: 746f65730a0a
2020-11-14 22:48:20.117488
Data: toes
不知何故,这个单一的 TCP 数据包被分成了 3 个较小的数据包。
你知道这是怎么发生的吗?
TCP 不是基于消息的协议,而是字节流。单个 send
并不意味着所有内容都将在单个 TCP 数据包中发送。同样,不能指望单个 recv
将匹配单个 send
.
如果你想要消息语义,你需要将它们添加到字节流之上。通常这是通过显式长度指示符、特殊分隔符或仅使用一条消息来完成的,即关闭连接将结束消息。然后你需要多次调用 recv
直到你收到完整的消息。
根据 的解释,这里是如何构建代码以接收整个消息:
def listenToClient(self, client, address):
size = 1024
while True:
try:
# Receive data from the client
data = ''
while True:
r = client.recv(size)
if not r:
break
data += r
print('CLIENT Data Received', client)
print(datetime.now())
print("Raw data received: ", data.hex())
Data: as the extra
except ConnectionAbortedError:
print(datetime.now())
print('CLIENT Disconnected:', client)
client.close()
return False
我在确定我托管的基于 Python 的 TCP 服务器上某些数据包拆分问题的原因时遇到了一些问题。
我的客户端连接到服务器后,它向服务器发送一个字符串,然后是 /n
。
数据包的 Wireshark 预览如下所示:
在这种情况下,您可以看到有效负载是"作为额外的特殊英国宝贝potatoes/n"
我的 TCP 服务器有以下接收代码:
def listenToClient(self, client, address):
size = 1024
while True:
try:
# Receive data from the client
data = client.recv(size)
print('CLIENT Data Received', client)
print(datetime.now())
print("Raw data received: ", data.hex())
Data: as the extra
except ConnectionAbortedError:
print(datetime.now())
print('CLIENT Disconnected:', client)
client.close()
return False
当收到上面的数据包时,打印如下:
CLIENT Data Received <socket.socket fd=428, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.0.16', 12345), raddr=('192.168.0.14', 47234)>
2020-11-14 22:48:20.087507
Raw data received: 617320746865206578747261
Data: as the extra
CLIENT Data Received <socket.socket fd=428, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.0.16', 12345), raddr=('192.168.0.14', 47234)>
2020-11-14 22:48:20.092495
Raw data received: 207370656369616c2062726974697368206261627920706f7461
Data: special british baby pota
CLIENT Data Received <socket.socket fd=428, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.0.16', 12345), raddr=('192.168.0.14', 47234)>
Raw data received: 746f65730a0a
2020-11-14 22:48:20.117488
Data: toes
不知何故,这个单一的 TCP 数据包被分成了 3 个较小的数据包。
你知道这是怎么发生的吗?
TCP 不是基于消息的协议,而是字节流。单个 send
并不意味着所有内容都将在单个 TCP 数据包中发送。同样,不能指望单个 recv
将匹配单个 send
.
如果你想要消息语义,你需要将它们添加到字节流之上。通常这是通过显式长度指示符、特殊分隔符或仅使用一条消息来完成的,即关闭连接将结束消息。然后你需要多次调用 recv
直到你收到完整的消息。
根据
def listenToClient(self, client, address):
size = 1024
while True:
try:
# Receive data from the client
data = ''
while True:
r = client.recv(size)
if not r:
break
data += r
print('CLIENT Data Received', client)
print(datetime.now())
print("Raw data received: ", data.hex())
Data: as the extra
except ConnectionAbortedError:
print(datetime.now())
print('CLIENT Disconnected:', client)
client.close()
return False