繁体   English   中英

asyncio 挂在 SSL 握手上

[英]asyncio hangs on SSL handshake

我目前正在将一些遗留代码迁移到 asyncio 并遇到有关 SSL 握手的问题。

我正在创建一个 SSL 服务器:

import os
import socket
import asyncio

from myexample import Connection

storage_path = '.' # Path where certificates are stored (self-signed)

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)

ssl_context.load_verify_locations(
    cafile = os.path.join(storage_path, 'root.cert')
)

ssl_context.load_cert_chain(
    certfile = os.path.join(storage_path, 'test-server.cert'), 
    keyfile  = os.path.join(storage_path, 'test-server.key')
)

ssl_context.verify_mode = ssl.VerifyMode.CERT_REQUIRED

loop = asyncio.new_event_loop()
loop.set_debug(True)
async def create_server_wrapped():
    server = await self.loop.create_server(
        Connection, # Connection class; Doesn't matter which one, issue also happens with examples from Python wiki
        '127.0.0.1', 
        20000,
        ssl = ssl_context,
        reuse_port      = True,
        reuse_address   = False,
        backlog         = 1000
    )
    await server.serve_forever()

loop.run_until_complete(create_server_wrapped())
loop.run_forever()

我通过普通的 sockets 连接:

import os
import ssl
import socket

storage_path = '.' # Path where certificates are stored (self-signed)

cert_file   = os.path.join(storage_path, 'client.cert')
pkey_file   = os.path.join(storage_path, 'client.key')

context = ssl.create_default_context(
    purpose = ssl.Purpose.SERVER_AUTH, 
    cafile = os.path.join(storage_path, 'root.cert')
)
context.load_cert_chain(cert_file, pkey_file)
context.check_hostname = False # Connecting by IP

plain_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

plain_socket.settimeout(5)
if not plain_socket.getsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE):
    plain_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    plain_socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 2)
    
sock = context.wrap_socket(plain_socket, server_side = False)

sock.connect(('127.0.0.1', 20700))

尝试连接时,大多数时候我得到一个socket.error: _ssl.c:1039: The handshake operation timed out

如果一个连接 go 通过,我可以看到服务器轮询花了很长时间:

DEBUG:asyncio:Using selector: EpollSelector
INFO:asyncio:<Server sockets=[<socket.socket fd=18, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('0.0.0.0', 20700)>]> is serving
INFO:asyncio:poll took 32642.889 ms: 1 events
DEBUG:asyncio:<Server sockets=[<socket.socket fd=18, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('0.0.0.0', 20700)>]> got a new connection from ('127.0.0.1', 55826): <socket.socket fd=19, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('127.0.0.1', 20700), raddr=('127.0.0.1', 55826)>
DEBUG:asyncio:<asyncio.sslproto.SSLProtocol object at 0x7ff7bf690ac8> starts SSL handshake
DEBUG:asyncio:poll 59999.647 ms took 0.027 ms: 1 events
DEBUG:asyncio:poll 59998.085 ms took 1.635 ms: 1 events
DEBUG:asyncio:<asyncio.sslproto.SSLProtocol object at 0x7ff7bf690ac8>: SSL handshake took 4.8 ms
DEBUG:asyncio:poll took 0.609 ms: 1 events
DEBUG:asyncio:poll took 1.107 ms: 1 events
DEBUG:asyncio:poll took 24.036 ms: 1 events
DEBUG:asyncio:<_SelectorSocketTransport fd=19 read=polling write=<idle, bufsize=0>> received EOF
DEBUG:asyncio:<asyncio.sslproto.SSLProtocol object at 0x7ff7bf690ac8> received EOF
Connection.connection_lost <class 'NoneType'> None

/edit:经过更多测试后,我发现这只发生在虚拟化环境中

问题在于启用reuse_port 虽然这是想要的行为(使用同一端口运行多个进程以进行负载平衡),但它会以某种方式导致问题。

禁用此功能并使用正常的负载平衡解决了我遇到的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM