Таймаут подключения с использованием метода sock_connect библиотеки asyncio

Вопрос или проблема

Когда я использую метод connect библиотеки socks напрямую, соединение устанавливается успешно, но когда я заменяю его на метод sock_connect библиотеки asynic, соединение истекает по времени.

import asyncio
import socks
from _socket import AF_INET, SOCK_STREAM


async def conn():
    parsed = (3, 'localhost', 7890, True, None, None)
    timeout = 10
    address = ('149.154.167.51', 443)

    sock = socks.socksocket(AF_INET, SOCK_STREAM)
    sock.set_proxy(*parsed)
    sock.settimeout(timeout)

    # используйте sock_connect
    await asyncio.wait_for(
        asyncio.get_running_loop().sock_connect(sock=sock, address=address),
        timeout=timeout
    )

    # используйте socks.connect_ex
    status = sock.connect_ex(address)
    print('статус подключения: ', status)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(conn())

когда я использую sock.connect_ex, я получаю:

статус подключения: 0

когда я использую sock_connect, я получаю:

asyncio.exceptions.TimeoutError

Я думаю, что эта ошибка вызвана истечением времени соединения.

Я отлаживал код и обнаружил, что sock_connect имеет две реализации: selector_events и proactor_events. Моя программа использует proactor_events. В конечном итоге используется метод connect в windos_events. Не знаю, влияет ли это на проблему.

Ответ или решение

Проблема времени ожидания при использовании метода sock_connect библиотеки asyncio

Если вы столкнулись с ошибкой asyncio.exceptions.TimeoutError при попытке установить соединение с использованием метода sock_connect из библиотеки asyncio, но с использованием метода connect_ex соединение проходит успешно, это может указывать на несколько возможных источников проблемы.

1. Различие в реализации методов подключения

Метод sock_connect предназначен для работы в асинхронном контексте и требует, чтобы сокет, с которым он работает, соответствовал определённым требованиям. Однако библиотека socks создаёт сокеты, которые могут не полностью соответствовать этим требованиям. Чаще всего метод connect_ex используется в синхронных программах и допускает некоторые "неформальные" сокеты.

2. Асинхронная реализация подключения

Когда вы используете await asyncio.wait_for(...), asyncio ожидает, что метод sock_connect будет полностью асинхронным. Однако, поскольку вы используете сокет, созданный с помощью socks, возможно, его обработка не соответствует ожиданиям asyncio. Таким образом, возникновение TimeoutError может означать, что сокет не смог установить соединение за отведённое время.

3. Проверка состояния сокета

Рекомендуется выполнить проверку готовности сокета перед попыткой подключения. Вы можете использовать метод sock.setblocking(False) для установки сокета в неблокирующий режим. Это даст возможность обработчику событий asyncio работать с сокетом более согласованно.

Вот пример того, как это можно сделать:

import asyncio
import socks
from _socket import AF_INET, SOCK_STREAM

async def conn():
    parsed = (3, 'localhost', 7890, True, None, None)
    timeout = 10
    address = ('149.154.167.51', 443)

    sock = socks.socksocket(AF_INET, SOCK_STREAM)
    sock.set_proxy(*parsed)
    sock.settimeout(timeout)
    sock.setblocking(False)  # Включаем неблокирующий режим

    try:
        await asyncio.wait_for(
            asyncio.get_running_loop().sock_connect(sock=sock, address=address),
            timeout=timeout
        )
        print("Successfully connected with sock_connect")
    except asyncio.TimeoutError:
        print("Connection timed out using sock_connect")
    except Exception as e:
        print(f"Error: {e}")

    # Использование socks.connect_ex как резервный вариант
    status = sock.connect_ex(address)
    print('connect status: ', status)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(conn())

4. Проблема с определением события

Ваше наблюдение о том, что используется proactor_events, может также влиять на обработку сокета. Важно удостовериться, что ваши асинхронные операции совместимы с выбранной моделью событий. Если возможно, попробуйте использовать альтернативную реализацию событий, такую как selector_events, чтобы увидеть, изменится ли поведение программы.

5. Заключение

Итак, если вы сталкиваетесь с TimeoutError, постарайтесь сначала отладить ваш сокет, убедитесь, что он работает в неблокирующем режиме, и проверьте режим событий, используемый вашим приложением. Эти простые шаги могут помочь вам найти и устранить проблему, связанную с таймаутом соединения при использовании метода sock_connect библиотеки asyncio.

Оцените материал
Добавить комментарий

Капча загружается...