Как я могу получить неблокирующий SSL-сокет в Asyncio?

#python-asyncio

#python-asyncio

Вопрос:

Итак, я могу довольно легко создать SSLSocket в asyncio:

 # Create a Socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setblocking(False)

# Connect
await loop.sock_connect(sock, host_address)  # type: ignore

# Create an SSL Context
ssl_context = ssl.create_default_context(cafile=PROXY_CA_BUNDLE)
...

# Wrap the SSL Context Around the Socket
def do_handshake(loop, sock, waiter):
    sock_fd = sock.fileno()
    try:
        sock.do_handshake()
    except ssl.SSLWantReadError:
        loop.remove_reader(sock_fd)
        loop.add_reader(sock_fd, do_handshake,
                        loop, sock, waiter)
        return
    except ssl.SSLWantWriteError:
        loop.remove_writer(sock_fd)
        loop.add_writer(sock_fd, do_handshake,
                        loop, sock, waiter)
        return

    loop.remove_reader(sock_fd)
    loop.remove_writer(sock_fd)
    waiter.set_result(None)

 waiter = loop.create_future()
 do_handshake(loop, sslconn, waiter)
 await waiter
  

Проблема в том, что SSLSocket нарушает неблокирующий интерфейс исходной библиотеки сокетов, поэтому он больше не совместим с другими методами asyncio, такими как asyncio.sock_sendall . Есть ли способ вместо этого обернуть сокет, чтобы он по-прежнему сохранял исходный интерфейс сокета?

Комментарии:

1. Почему вы пытаетесь использовать низкоуровневый loop.remove_reader() и loop.add_reader() API вместо streams API? Например, loop.create_connection поддерживает создание SSL-соединений — вы можете это использовать?

2. К сожалению, я не могу использовать streams API; Мне нужно передать сокет в приложение Cython, которое ожидает сокет Python по умолчанию.

3. Ожидает ли приложение Cython блокирующий или неблокирующий сокет? Кроме того, если сокет ожидается приложением, зачем вообще подключать его к циклу событий asyncio?

4. Неблокирующее гнездо (как указано выше). Usecase в основном использует asyncio для создания прокси-соединения (HTTP), затем нужен исходный сокет для протокола cython.

5. Если единственная проблема заключается в том, что asyncio не работает с обернутым сокетом, тогда я бы вызвал высокоуровневый API и затем получил используемый им сокет. Например, создайте подкласс SSLContext и предоставьте wrap_socket impl, который сохраняет SSLSocket созданное super().wrap_socket(...) в выбранном вами месте. После вызова open_connection с ssl=<your context> помощью и настройки прокси-сервера вы могли бы извлечь SSLSocket и передать его Cython.