Вопрос или проблема
Когда я использую метод 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.