本教程是对我的要点Python Websockets SSL with Let's Encrypt
的解释。
随着2008年HTML5的推出,该技术立即开始流行。根据W3C的说法,Websocket的基本定义是 - 一个接口,该接口使Web应用程序能够通过服务器端进程维护双向通信。
在本简短的教程中,我将向您展示如何在其上启用使用SSL的Websocket服务器。这允许您的插座服务器在HTTPS地址上运行。
设置
我们将使用asyncio
库,用于WebSocket服务器实现将使用websockets
库。
自Python 3.4以来,asyncio
库预先包含Python发行版。要安装websockets
库,您可以使用以下命令:
pip install websockets
接下来,我们将研究如何生成SSL证书文件。
使用让我们加密生成证书和密钥文件
在可以通过Python脚本运行的Websocket上启用SSL之前,您必须为域生成证书文件。
此步骤的基本要旨是获取让您的域签名认证,并将其存储在服务器上的Python Websocket正在运行的位置。
这是关于How To Use Certbot Standalone Mode to Retrieve Let's Encrypt SSL Certificates on Ubuntu 20.04的绝佳快速教程。
使证书文件可访问
正确生成文件后,您需要使运行Python WebSocket脚本的当前用户可以访问它们。
在上一步中,如果certbot
将证书文件存储在/etc/letsencrypt/live/your_domain
位置,则在文件夹上执行ls
时应该可以看到4个文件 -
~$ ls /etc/letsencrypt/live/your_domain
cert.pem chain.pem fullchain.pem privkey.pem README
要更改证书文件的所有者,请使用以下命令:
~$ sudo chown -R $(id -u):$(id -g) /etc/letsencrypt/live/your_domain
接下来,确保将正确的权限应用于文件夹:
~$ sudo chmod -R 400 /etc/letsencrypt/live/your_domain
我们现在很高兴从Python WebSocket脚本读取这些文件。
创建服务器脚本
虽然您的WebSocket Server脚本与大多数Barebones的实现有所不同,但这是您的一个适合您 -
创建一个名为socket_server.py
的文件。然后,进行所有必要的进口。
#!/usr/bin/env python
# WS server example that synchronizes state across clients
import asyncio
import json
import logging
import websockets
import ssl
logging.basicConfig()
接下来,让我们为此脚本配置SSL,如下所示 -
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
# Generate with Lets Encrypt, chown to current user and 400 permissions
ssl_cert = "/etc/letsencrypt/live/your_domain/fullchain.pem"
ssl_key = "/etc/letsencrypt/live/your_domain/privkey.pem"
ssl_context.load_cert_chain(ssl_cert, keyfile=ssl_key)
上面的代码将脚本配置为运行TLS服务器,并在certbot
生成的文件夹中可用的证书。
接下来,我们定义用于通知客户端服务器并从中获取信息的功能。
STATE = {"value": 0}
USERS = set()
def state_event():
return json.dumps({"type": "state", **STATE})
def users_event():
return json.dumps({"type": "users", "count": len(USERS)})
async def notify_state():
if USERS: # asyncio.wait doesn't accept an empty list
message = state_event()
await asyncio.wait([user.send(message) for user in USERS])
async def notify_users():
if USERS: # asyncio.wait doesn't accept an empty list
message = users_event()
await asyncio.wait([user.send(message) for user in USERS])
之后,我们需要添加从Websocket注册和注册客户端的函数。
async def register(websocket):
USERS.add(websocket)
await notify_users()
async def unregister(websocket):
USERS.remove(websocket)
await notify_users()
这样做,让我们实现一个函数,该函数从客户端获取状态更新请求并执行。
async def counter(websocket, path):
# register(websocket) sends user_event() to websocket
await register(websocket)
try:
await websocket.send(state_event())
async for message in websocket:
data = json.loads(message)
if data["action"] == "minus":
STATE["value"] -= 1
await notify_state()
elif data["action"] == "plus":
STATE["value"] += 1
await notify_state()
else:
logging.error("unsupported event: {}", data)
finally:
await unregister(websocket)
最后,我们运行服务器。
start_server = websockets.serve(counter, "0.0.0.0", 6789, ssl=ssl_context)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
您如何将服务器公开到Internet,我将将其放在您的用例上。但是,您可以在Websockets - Deploy behind nginx上探索本教程。
实施客户页面
要测试上述WebSocket脚本,您可以旋转自己的客户端脚本或随时使用我提供的socket_client.html文件。
确保更新客户端文件中的以下行以指向您的实时服务器 -
websocket = new WebSocket("wss://localhost:6789/");
请注意,我们在此处使用wss://
协议,而不是ws://
协议,该协议通常在Internet上的其他教程中找到。
结论
这是我尝试解释一年多以前提出的要点的尝试。希望它可以帮助您比我首先写的过程更容易完成整个过程。
确保给我关于此博客的反馈!