第十章:使用进程、线程和协程提供并发性-asyncio:异步I/O、事件循环和并发工具-使用SSL

本文介绍如何在Python的AsyncIO框架中使用SSL进行安全通信。通过创建自签名证书和密钥,我们更新了回送服务器和客户端,实现了SSL连接。文章详细解释了如何配置SSLContext,禁用主机名验证,以及在客户端和服务器间安全地发送和接收数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

10.5.10 使用SSL
asyncio提供了对SSL的内置支持,可以在套接字上启用SSL连接。向创建服务器或客户端连接的协程传递一个SSLContext实例就会启用这个内置支持,提供应用可以使用的套接字之前一定要先完成SSL协议设置。
可以进一步更新上一节中基于协程的回送服务器和客户端,再做几个小小的修改。第一步是创建证书和密钥文件。可以用哦如下命令创建一个自签名证书:
$ openssl req -newkey rsa:2048 -nodes -keyout pymotw.key
-x509 -days 365 -out pymotw.crt
openssl命令会提示输入多个值用来生成证书,然后生成所请求的输出文件。在上一节服务器示例中建立不安全的套接字时使用了start_server()创建监听套接字。

factory = asyncio.start_server(echo,*SERVER_ADDRESS)
server = event_loop.run_until_complete(factory)

为了增加加密,要用刚才生成的证书和密钥创建一个SSLContext,然后将这个上下文传递到start_server()

# The certificate is created with pymotw.com as the hostname.
# This name will mot match when the example code runs elsewhere,
# so disable hostname verification.
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.check_hostname = False
ssl_context.load_cert_chain('pymotw.crt','pymotw.key')

# Create the server and let the loop finish the coroutine before
# starting the real event loop.
factory = asyncio.start_server(echo,*SERVER_ADDRESS,ssl=ssl_context)

客户端中需要做类似的修改。老版本中使用open_connection()来创建与服务器连接的套接字。

reader,writer = await asyncio.open_connection(*address)

同样需要一个SSLContext来保护套接字客户端的安全。这里对客户身份没有强制要求,所以只需要加载证书。

# The certificate is created with pymotw.com as the hostname.
# This name will not match when the example code runs
# elsewhere,so disable hostname verification.
ssl_context = ssl.create_default_context(
    ssl.Purpose.SERVER_AUTH,
    )
ssl_context.check_hostname = False
ssl_context.load_verify_locations('pymotw.crt')
reader,writer = await asyncio.open_connection(
    *server_address,ssl=ssl_context)

客户端中还需要做另一个很小的修改。由于SSL连接不支持发送文件末尾(EOF)通知,所以客户端使用一个NULL字节作为消息终止符。起那么老版本的客户端使用write_eof()发送这个通知。

# This could be writer.writelines() except that
# would make it harder to show each part of the message
# being sent.
for msg in  messages:
    writer.write(msg)
    log.debug('sending {!r}'.format(msg))
if writer.can_write_eof():
    writer.write_eof()
await writer.drain()
# 新版本则发送一个0字节(b'\x00')来指示消息结束。
# This could be writer.writerlines() except that
# would make it harder EOF,so send a null byte to indicate
# the end of the meaasge.
writer.write(b'\x00')
await writer.drain()

服务器中的echo()协程必须查找NULL字节,并在接收到这个字节时关闭客户连接。

async def echo(reader,writer):
    address = writer.get_extra_info('peername')
    log = logging.getLogger('echo_{}_{}'.format(*address))
    log.debug('connection accepted')
    while True:
        data = await reader.read(128)
        terminate = data.endswith(b'\x00')
        data = data.rstrip(b'\x00')
        if data:
            log.debug('received {!r}'.format(data))
            writer.write(data)
            await writer.drain()
            log.debug('sent {!r}'.format(data))
        if not data or terminate:
            log.debug('message terminated closing connection')
            writer.close()
            return
在一个窗口中运行服务器,在另一个窗口中运行客户端。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值