我正在使用python3.7和异步创建到本地网络上的一些硬件的TCP连接,与所有硬件一样,这些硬件可能被断开或被简单地切换。
如果硬件断开,我注意到使用asyncio.open_connection()
大约需要~3s来引发OSError
import asyncio
import logging
logging.basicConfig(level='INFO', format='%(asctime)s %(message)s')
async def main(host, port):
while True:
try:
logging.info('trying to connect to %s:%d', host, port)
r, w = await asyncio.open_connection(host, port)
logging.info('connected')
break
except Exception as error:
logging.error('error: %r', error)
asyncio.run(main('cryoctrl01', 5000))
产出:
$ python test.py
2020-05-05 18:31:04,983 trying to connect to cryoctrl01:5000
2020-05-05 18:31:08,039 error: OSError(113, "Connect call failed ('192.168.1.12', 5000)")
2020-05-05 18:31:08,039 trying to connect to cryoctrl01:5000
2020-05-05 18:31:11,111 error: OSError(113, "Connect call failed ('192.168.1.12', 5000)")
2020-05-05 18:31:11,111 trying to connect to cryoctrl01:5000
2020-05-05 18:31:14,183 error: OSError(113, "Connect call failed ('192.168.1.12', 5000)")
...
正如我所知道的,我在一个本地网络上,我想减少这一次,所以我把代码包装在这样的asyncio.wait_for()
上:
import asyncio
import logging
logging.basicConfig(level='INFO', format='%(asctime)s %(message)s')
async def main(host, port, timeout):
while True:
try:
logging.info('trying to connect to %s:%d', host, port)
coro = asyncio.open_connection(host, port)
r, w = await asyncio.wait_for(coro, timeout)
logging.info('connected')
break
except Exception as error:
logging.error('error: %r', error)
asyncio.run(main('cryoctrl01', 5000, 0.5))
但是现在我有一个不一致的行为:有时我得到了预期的Timeout
错误,但有时我得到一个OSError
:
$ python test.py
2020-05-05 18:56:18,035 trying to connect to cryoctrl01:5000
2020-05-05 18:56:18,537 error: TimeoutError()
2020-05-05 18:56:18,537 trying to connect to cryoctrl01:5000
2020-05-05 18:56:19,038 error: TimeoutError()
2020-05-05 18:56:19,038 trying to connect to cryoctrl01:5000
2020-05-05 18:56:19,540 error: TimeoutError()
2020-05-05 18:56:19,540 trying to connect to cryoctrl01:5000
2020-05-05 18:56:20,042 error: TimeoutError()
2020-05-05 18:56:20,043 trying to connect to cryoctrl01:5000
2020-05-05 18:56:20,545 error: TimeoutError()
2020-05-05 18:56:20,545 trying to connect to cryoctrl01:5000
2020-05-05 18:56:21,047 error: TimeoutError()
2020-05-05 18:56:21,047 trying to connect to cryoctrl01:5000
2020-05-05 18:56:21,095 error: OSError(113, "Connect call failed ('192.168.1.12', 5000)")
2020-05-05 18:56:21,095 trying to connect to cryoctrl01:5000
2020-05-05 18:56:21,597 error: TimeoutError()
2020-05-05 18:56:21,597 trying to connect to cryoctrl01:5000
2020-05-05 18:56:22,098 error: TimeoutError()
2020-05-05 18:56:22,098 trying to connect to cryoctrl01:5000
2020-05-05 18:56:22,600 error: TimeoutError()
2020-05-05 18:56:22,600 trying to connect to cryoctrl01:5000
2020-05-05 18:56:23,102 error: TimeoutError()
2020-05-05 18:56:23,102 trying to connect to cryoctrl01:5000
2020-05-05 18:56:23,604 error: TimeoutError()
2020-05-05 18:56:23,604 trying to connect to cryoctrl01:5000
2020-05-05 18:56:24,106 error: TimeoutError()
2020-05-05 18:56:24,106 trying to connect to cryoctrl01:5000
2020-05-05 18:56:24,167 error: OSError(113, "Connect call failed ('192.168.1.12', 5000)")
2020-05-05 18:56:24,167 trying to connect to cryoctrl01:5000
2020-05-05 18:56:24,669 error: TimeoutError()
2020-05-05 18:56:24,669 trying to connect to cryoctrl01:5000
我注意到,这似乎也发生在每隔3s。这是操作系统的行为吗?为了有一致的行为,我应该如何修改我的代码?
发布于 2020-05-06 08:12:38
只有在实际超时时才能得到TimeoutErrr
。如果您查看启动连接和非超时错误之间的时间差,您将看到它们发生在小于0.5s的超时时间内。检查超时并不能保护您免受其他网络错误的影响,因此您不能期望一致性--您只需处理这两种情况。
如果使用%s
而不是%r
打印错误,您将看到来自系统的错误消息。Errno 113可能是“无主机路由”,这可能表明您的一方出现了短暂的网络故障。您需要捕获OSError
并决定如何处理它们,典型的方法是在适当的延迟之后重试连接。
https://stackoverflow.com/questions/61618818
复制相似问题