Как отловить ошибку сброса соединения из функции l oop .sock_recv ()? - PullRequest
1 голос
/ 10 июля 2020

Я пытаюсь отловить ошибку сброса соединения из функции l oop .sock_recv при попытке чтения байтов из клиентского сокета. Я тестирую сценарий, когда сервер закрывает соединение после указанного c тайм-аута, функция sock_recv (client_socket, max_re c) выдает ошибку сброса соединения, как и ожидалось, но я не могу отловить ее в коде. Скорее, если я заменю try / except на try /, наконец, он работает лучше, но не всегда дает ожидаемый ответ.

 try:
            done, pending = await asyncio.wait([loop.sock_recv(client_sock, max_rec)], timeout = 7)

        except ConnectionResetError:
            log.info(f"Got the connection reset which means the server socket closed the connection after {timeout} seconds")
            is_connection_reset = True

Журналы:

[[0m ERROR    16:43:05| asyncio                        - Task exception was never retrieved
[[36mtest-client_1  |^[[0m future: <Task finished name='Task-67' coro=<BaseSelectorEventLoop.sock_recv() done, defined at /usr/local/lib/python3.8/asyncio/selector_events.py:349> exception=ConnectionResetError(104, 'Connection reset by peer')>(base_events.py, line 1707)
[[36mtest-client_1  |[[0m Traceback (most recent call last):
[[36mtest-client_1  |[[0m   File "/usr/local/lib/python3.8/asyncio/selector_events.py", line 368, in sock_recv
[[36mtest-client_1  |[[0m     return await fut
[[36mtest-client_1  |[[0m   File "/usr/local/lib/python3.8/asyncio/selector_events.py", line 379, in _sock_recv
[[36mtest-client_1  |[[0m     data = sock.recv(n)
[[36mtest-client_1  |[[0m ConnectionResetError: [Errno 104] Connection reset by peer

1 Ответ

0 голосов
/ 13 июля 2020

Вы должны заменить asyncio.wait([...], timeout=7) на asyncio.wait_for:

try:
    data = await asyncio.wait_for(
        loop.sock_recv(client_sock, max_rec), 7)
except ConnectionResetError:
    ... handle connection reset
except asyncio.TimeoutError:
    ... handle timeout

Разница между asyncio.wait_for(x, 7) и asyncio.wait([x], timeout=7) состоит в том, что wait_for отменит ожидаемый, если истекло время ожидания. С другой стороны, asyncio.wait() оставит его работать в фоновом режиме (и вернет его в наборе pending).

В вашем случае, скорее всего, произойдет то, что sock_recv поднимет ConnectionResetError после более 7сек. Как написано, ваш код обрабатывает ошибку, только если она возникает в течение первых 7 секунд. Если это произойдет позже, оно будет вызвано в фоновой задаче и сообщено обработчиком исключений по умолчанию.

Кстати, вам, вероятно, не следует использовать sock_recv напрямую; это низкоуровневый API, о котором должны заботиться только разработчики новых циклов событий. В коде приложения следует использовать asyncio.open_connection.

...