send()via blocking socket超时,但消息已到达目标

2024-09-21 00:18:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在处理点对点通信系统(用python3.5编写和运行)中的分布式“死锁”情况。在这个系统中,每个节点与每个节点保持2个所谓的inconoutconn连接。我使用select.poll()执行多路复用。因此,有时会发生以下死锁:如果两个连接的对等方都试图通过outconn发送到另一个,则每个对等方的select.poll()循环在send()中被阻塞,因此另一方无法在incon连接上接收()

我处理这种死锁的方法是在outconnn的套接字上设置timeout(),这似乎是可行的。然而,有趣的是,消息似乎能够在套接字超时后到达目的地。以下是两个节点的示例日志:

节点A(192.168.56.109)

INFO: [2016-11-02 11:08:05,172] [COOP] Sending ASK_COOP [2016-11-02 11:08:05.172643] to 192.168.56.110 for segment 2.

WARNING: [2016-11-02 11:08:06,173] [COOP] Cannot send to 192.168.56.110. Error: timed out

INFO: [2016-11-02 11:08:06,174] [COOP] Message from 192.168.56.110 is available on 10.

INFO: [2016-11-02 11:08:06,174] [COOP] Get HEARTBEAT [2016-11-02 11:08:04.503723] from 192.168.56.110 for segment 2.

节点B(192.168.56.110)

INFO: [2016-11-02 11:08:04,503] [COOP] Sending HEARTBEAT [2016-11-02 11:08:04.503723] to 192.168.56.109 for segment 2.

WARNING: [2016-11-02 11:08:05,505] [COOP] Cannot send to 192.168.56.109. Error: timed out

INFO: [2016-11-02 11:08:05,505] [COOP] Message from 192.168.56.109 is available on 11.

INFO: [2016-11-02 11:08:05,505] [COOP] Get ASK_COOP [2016-11-02 11:08:05.172643] from 192.168.56.109 for segment 2.

我能知道为什么吗?顺便问一下,我处理这种僵局的方式是一种好的做法吗?如果不是,那么避免这种分布式死锁的最佳实践是什么


Tags: tofrominfosendfor节点系统分布式
1条回答
网友
1楼 · 发布于 2024-09-21 00:18:41

根据我的经验,避免此问题的最佳实践是始终使用非阻塞I/O。如果您的应用程序从不在send()或recv()内阻塞,那么就不会出现死锁(至少,不是您描述的那种死锁)

当然,非阻塞I/O带来了它自己的复杂性,特别是,您的代码需要能够正确处理部分发送和部分接收。实际上,这意味着您的应用程序的事件循环可能如下所示(伪代码):

while true:
   block in select() until at least one socket is ready-for-read (or ready-for write, if you have data you want to send on that socket)

   for each ready-for-read socket:      
      read as many bytes as you can (without blocking) into a FIFO receive buffer that you have associated with that socket
      parse as many complete messages as you can out of the beginning of the FIFO buffer 
      (pop the parsed bytes out of the FIFO when you're done with them)

   for each ready-for-write socket:
      send as many bytes as you can (without blocking) from a FIFO send buffer that you have associated with that socket
      (pop the sent bytes out of the FIFO when you're done with them)

在这种设计中,每当你的应用程序生成了新的数据,它想在套接字上发送,它不应该直接调用send();相反,它应该将该数据附加到与该套接字相关联的FIFO发送缓冲区的末尾,并且上面的事件循环将允许尽快发送数据(当然,在发送任何已经存在于FIFO中的数据之后),而不会阻止事件循环执行它可能具有的任何其他职责

在最坏的情况下(一个非常慢的TCP连接,你想通过它发送大量数据),FIFO可能会变大(使用额外的内存),但它永远不会“死锁”

相关问题 更多 >

    热门问题