Python TCP服务器接收拆分为多个数据包的单个TCP数据包
在我托管的基于Python的TCP服务器上,我很难确定某些数据包分裂问题的原因 我的客户端连接到服务器后,会向服务器发送一个字符串,后跟Python TCP服务器接收拆分为多个数据包的单个TCP数据包,python,sockets,tcp,Python,Sockets,Tcp,在我托管的基于Python的TCP服务器上,我很难确定某些数据包分裂问题的原因 我的客户端连接到服务器后,会向服务器发送一个字符串,后跟/n 数据包的Wireshark预览如下所示: 在本例中,您可以看到有效负载是“作为特别的英国婴儿土豆/n” 我的TCP服务器具有以下接收代码: def listenToClient(self、client、address): 大小=1024 尽管如此: 尝试: #从客户端接收数据 数据=client.recv(大小) 打印('已接收客户端数据',客户端) 打
/n
数据包的Wireshark预览如下所示:
在本例中,您可以看到有效负载是“作为特别的英国婴儿土豆/n”
我的TCP服务器具有以下接收代码:
def listenToClient(self、client、address):
大小=1024
尽管如此:
尝试:
#从客户端接收数据
数据=client.recv(大小)
打印('已接收客户端数据',客户端)
打印(datetime.now())
打印(“收到的原始数据:”,data.hex())
数据:作为额外数据
除ConnectionAbortedError外:
打印(datetime.now())
打印('客户端已断开连接:',客户端)
client.close()
返回错误
当收到上述数据包时,它将打印以下内容:
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
接收到客户端数据
2020-11-14 22:48:20.087507
收到的原始数据:61732074685206578747261
数据:作为额外数据
收到的客户数据
2020-11-14 22:48:20.092495
收到的原始数据:207370656369616c2062726974697368206261627920706f7461
资料来源:英国特殊婴儿波塔
收到的客户数据
收到的原始数据:746f65730a0a
2020-11-14 22:48:20.117488
数据:脚趾
不知何故,这个TCP数据包被分成了3个较小的数据包
你知道这是怎么发生的吗?TCP不是一个基于消息的协议,而是一个字节流。单个
发送
并不意味着所有内容都将在单个TCP数据包内发送。同样,不能指望单个recv
与单个send
匹配
如果需要消息语义,则需要在字节流的顶部添加这些语义。通常,这是通过显式长度指示器、特殊分隔符或只有一条消息来完成的,即关闭连接将结束消息。然后需要多次调用recv,直到得到完整的消息。TCP不是基于消息的协议,而是字节流。单个
发送
并不意味着所有内容都将在单个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
根据此处的说明,您可以如何构造代码以接收整个消息:
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
请看我在这里的评论。。。请看我在这里的评论。。。谢谢你的及时答复。在本例中,我的“特殊分隔符”是附加在每个句子末尾的
\n
。是否有一种方法可以使recv阻塞并继续连接接收到的流,直到它遇到此\n
?我不想关闭连接,因为为此我需要一个长寿命的TCP连接:)@OscarVanL:recv
在出现特定字符之前无法只读。您需要自己实现这一点。请参阅示例,了解有关如何操作的一些想法。谢谢,这看起来很完美。我会试试:)我通过修改这个答案使它起作用了,谢谢!谢谢你的及时答复。在本例中,我的“特殊分隔符”是附加在每个句子末尾的\n
。是否有一种方法可以使recv阻塞并继续连接接收到的流,直到它遇到此\n
?我不想关闭连接,因为为此我需要一个长寿命的TCP连接:)@OscarVanL:recv
在出现特定字符之前无法只读。您需要自己实现这一点。请参阅示例,了解有关如何操作的一些想法。谢谢,这看起来很完美。我会试试:)我通过修改这个答案使它起作用了,谢谢!不能保证字节流不会在UTF-8多字节字符的中间被分割,所以你不应该解码它直到你确定有一个完整的消息。此代码还假设您一直在接收,直到套接字关闭为止,因此只能接收一条消息。@MarkTolonen关于我代码中的解码部分,您完全正确。另一方面,关于你评论的第二部分,这个问题涉及一个TCP数据包,所以只有一条消息,除非我错了。我提到发送一条消息后加上一个\n,之后不一定要关闭套接字。它确实需要一个缓冲层,从流中填充缓冲区,直到看到换行符,然后将缓冲区的部分返回到并包括换行符。此后,缓冲区中剩余的任何内容将是下一条消息的一部分。不能保证字节流不会在UTF-8多字节字符的中间被分割,所以在确定完整消息之前,不应该对其进行解码。此代码还假设您一直在接收,直到套接字关闭为止,因此只能接收一条消息。@MarkTolonen关于我代码中的解码部分,您完全正确。另一方面,关于你评论的第二部分,这个问题涉及一个TCP数据包,所以只有一条消息,除非我错了。我提到发送一条消息后加上一个\n,之后不一定要关闭套接字。它确实需要一个缓冲层,从流中填充缓冲区,直到看到换行符,然后返回部分