Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python异步IO SSL传输未关闭_Python_Networking_Python Asyncio_Tls1.2_Python 3.8 - Fatal编程技术网

Python异步IO SSL传输未关闭

Python异步IO SSL传输未关闭,python,networking,python-asyncio,tls1.2,python-3.8,Python,Networking,Python Asyncio,Tls1.2,Python 3.8,我正在尝试使用python asyncio协议构建到Windows10VM的RDP连接。在第一次消息交换协商TLS连接后,必须将连接升级到TLS,为此我使用start_TLS。在调用transport.close()尝试在第二个数据包之后关闭连接之前,一切正常。文档中说,在刷新所有输出缓冲区()之后,使用None调用协议实例的“connection_lost”方法。在我的例子中,调用close()并完成调用,但从未调用connection_lost(),这使我的应用程序等待服务器在超时后发送RS

我正在尝试使用python asyncio协议构建到Windows10VM的RDP连接。在第一次消息交换协商TLS连接后,必须将连接升级到TLS,为此我使用start_TLS。在调用transport.close()尝试在第二个数据包之后关闭连接之前,一切正常。文档中说,在刷新所有输出缓冲区()之后,使用None调用协议实例的“connection_lost”方法。在我的例子中,调用close()并完成调用,但从未调用connection_lost(),这使我的应用程序等待服务器在超时后发送RST,这将正确触发connection_lost。 如果服务器协商TLS 1.2,而不是TLS 1.3,则会发生这种情况。我检查了输出缓冲区是否为空,并查看了cpython源代码,但无法确定它挂起的位置。通过Wireshark,我发现调用close()时不会发生任何事情,我的客户机不会向服务器发送任何信息。 我正在Ubuntu 20.04上使用python 3.8.5

有人知道为什么不调用connection_lost吗

请参见下面我的最低工作示例:

#!/usr/bin/env python3

import asyncio
import ssl
import binascii

# first two packets for RDP, tested thoroughly
PACKET_NEGO = binascii.unhexlify("0300002d28e00000000000436f6f6b69653a206d737473686173683d6c696f6e6c656c0d0a0100080001000000")
PACKET_CONN = binascii.unhexlify("030001ca02f0807f658201be0401010401010101ff30200202002202020002020200000202000102020000020200010202ffff020200023020020200010202000102020001020200010202000002020001020204200202000230200202ffff0202fc170202ffff0202000102020000020200010202ffff020200020482014b000500147c00018142000800100001c00044756361813401c0d800040008000004000301ca03aa09040000280a00006e006f0076006f007300690062006900720073006b000000000000000000000004000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ca01000000000018000b0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002c00c00000000000000000003c0440005000000636c697072647200c0a00000726470736e640000c0000000736e646462670000c0000000726470647200000080800000647264796e766300c000000004c00c000d00000000000000")

class RDPConnection(asyncio.Protocol):
    def __init__(self, on_con_close, on_tls, loop, ip):
        self.on_tls = on_tls
        self.on_con_close = on_con_close
        self.loop = loop
        self.state = 0
        self.ip = ip

    def connection_made(self, transport):
        self.transport = transport

        if self.state == 0:
            transport.write(PACKET_NEGO) # write first packet on initial connection
        else:
            transport.write(PACKET_CONN) # write second packet on TLS connection

    def data_received(self, data):
        if self.state == 0:
            self.state += 1
            self.on_tls.set_result(True) # start TLS connection
        else:
            print("closing connection")
            self.transport.close()
            print("closed connection")
        
    def connection_lost(self, exc):
        print("connection lost called")
        self.on_con_close.set_result(True)
        print("{}: {}".format(self.ip, exc))

    def _timeout(self):
        if self.transport:
            self.transport.close()
        
async def handle_connection(loop, ip, timeout):
    on_tls = loop.create_future() # called when connection is ready to be upgraded to TLS
    con_close = loop.create_future() # called when connection is closed

    try:
        transport, protocol = await asyncio.wait_for(loop.create_connection(lambda: RDPConnection(con_close, on_tls, loop, ip), ip, 3389), timeout=timeout)
    except:
        return
    await on_tls # wait for first response

    ssl_ctx = ssl._create_unverified_context() # VM uses self signed certificate
    try:
        transport2 = await asyncio.wait_for(loop.start_tls(transport, protocol, ssl_ctx), timeout=timeout) # upgrade to TLS
        protocol.connection_made(transport2) # set TLS transport
    except:
        return
    await con_close # wait for connection_lost to be called
    return

async def main():
    loop = asyncio.get_running_loop()
    await handle_connection(loop, "my VM", 10)

asyncio.run(main())
我的机器上的输出:

closing connection
closed connection
connection lost called
my VM: [Errno 104] Connection reset by peer
请注意,“调用连接丢失”仅在服务器重置连接时(约30秒后)才会调用。

transport.abort()
是您的朋友

transport.abort()
是你的朋友


如果你能添加更多细节,那就更好了……如果你能添加更多细节,那就更好了。。。。