如果服务器使用pickle python发送消息太快,则客户端不会收到所有消息

时间:2018-11-10 02:12:08

标签: sockets networking tcp

如果发件人发送得太快,我的客户端将无法接收这两条消息。

sender.py

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)


sock.bind(('', int(port)))
sock.listen(1)

conn, addr = sock.accept()
#conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

# sends message 1 and message 2
conn.send(pickle.dumps(message1))
#time.sleep(1)
conn.send(pickle.dumps(message2))

消息1和消息2均为腌制对象。

client.py

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((ip,int(port)))

message1 = pickle.loads(sock.recv(1024))

print(message1)

message2 = pickle.loads(sock.recv(1024)) 

按原样运行此代码时,我可以打印出message1,但无法从发件人接收message2。套接字在message2处阻塞。

此外,如果我在发件人附带的代码中取消注释time.sleep(1),我将能够很好地接收两条消息。不确定是什么问题。我试图每次通过设置TCP_NODELAY来刷新我的TCP缓冲区,但这没有用。不知道实际发生了什么?我如何确保我收到两条消息

1 个答案:

答案 0 :(得分:1)

您的代码假设服务器端的每个send与客户端端的recv相匹配。但是,TCP是字节流,而不是基于消息的协议。这意味着您的第一个recv很可能已经包含了第二个send的数据,这些数据可能被pickle.loads丢弃,成为腌制数据之后的垃圾。第二个recv将仅接收剩余数据(或由于已接收所有数据而仅阻塞),因此pickle.loads将失败。

处理这种情况的常用方法是在TCP字节流的顶部构造一个消息协议。例如,这可以通过以下方式来实现:在发送时为每条消息添加固定长度的前缀(例如,使用struct.pack('L',...)作为4字节uint),并为读取而首先读取固定长度的值,然后使用给定大小。