python несогласованное поведение asyncio.open_connection () по истечении времени ожидания - PullRequest
0 голосов
/ 05 мая 2020

Я использую python 3.7 с asyncio для создания TCP-соединения с некоторым оборудованием в локальной сети, которое, как и все оборудование, может быть отключено или просто отключено.

В случае отключения оборудования , Я заметил, что использование asyncio.open_connection() занимает около 3 секунд, чтобы поднять 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

Я заметил, что это происходит примерно каждые 3 секунды. Это происходит из-за ОС? Как мне изменить свой код, чтобы вести себя последовательно?

1 Ответ

0 голосов
/ 06 мая 2020

Вы получаете TimeoutErrr только при фактических тайм-аутах. Если вы посмотрите на разницу во времени между установкой соединения и ошибками, не связанными с тайм-аутом, вы увидите, что они возникают менее чем за 0,5 с. Проверка тайм-аута не защищает вас от других сетевых ошибок, поэтому вы не можете ожидать согласованности - вам просто нужно обработать оба условия.

Если вы напечатаете ошибку с помощью %s вместо %r вы увидите сообщение об ошибке, исходящее от системы. Errno 113, вероятно, «нет маршрута к хосту», что может указывать на временный сбой сети на вашей стороне. Вам нужно поймать OSError и решить, как их обрабатывать, типичный подход - повторить попытку подключения после соответствующей задержки.

...