python - 通过安全 (SSL) WebSockets 从 Python 向 Python 发送消息
问题描述
我有一个嵌入 Python 脚本的 C++ 应用程序。C++ 应用程序将cv::Mat
图像发送到 Py 脚本,然后运行一些图像识别(通过 CNN)。基本思想可以在我的 gist中找到。
然后我的 Python 脚本想要通过带有 SSL 的安全 WebSocket 将 CNN 预测的结果发送到另一个应用程序(我相信是 Unity)。
目前我无法访问实际的 Unity 应用程序,因此我必须使用简单的 Python 服务器应用程序测试实际的“发送”部分。
我对 Python 中的套接字和 SSL 没有太多经验(或知识),所以我希望能得到一些帮助。
如果我只使用不安全的 HTTP 连接,一切都会正常工作,但是当我尝试引入 HTTPS 和 SSL 时,我会遇到问题。
服务器端:
在最后一次尝试中,我使用了以下服务器脚本(取自此处):
import asyncio
import pathlib
import ssl
import websockets
async def hello(websocket, path):
name = await websocket.recv()
print(f"< {name}")
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ssl_context.load_cert_chain(
pathlib.Path(__file__).with_name('cert.pem'),
pathlib.Path(__file__).with_name('key_wopasswd.pem'))
start_server = websockets.serve(hello, 'localhost', 443, ssl=ssl_context)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
证书和密钥文件是由一位负责实际接收 Unity 应用程序的同事提供给我的。
客户端:
之后,我尝试像这样连接和发送消息(片段 1):
import json
import http.client, ssl
import time
ws = None
def send(msg="lol"):
global ws
if ws is None:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ssl_context.load_cert_chain('cert.pem', 'key_wopasswd.pem')
ws = http.client.HTTPSConnection("localhost", 443, context=ssl_context)
ws.connect()
print("connected successfully!")
else:
jsonString = json.dumps({"Time":int(time.time()), "Message":msg})
ws.send(jsonString.encode('utf-8'))
在这种情况下,根本没有任何反应。
或者像这样(片段 2):
import websocket, ssl
import time
ws = None
def send(msg="lol"):
global ws
if ws is None:
ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_REQUIRED,
"ssl_version": ssl.PROTOCOL_TLSv1,
"certfile": "cert.pem",
"keyfile": "key_wopasswd.pem"})
ws.connect("wss://localhost:443")
else:
jsonString = json.dumps({"Time":int(time.time()), "Message":msg})
ws.send(jsonString.encode('utf-8'))
在这种情况下,我收到以下错误:
Traceback (most recent call last):
File ".\client2.py", line 21, in send
ws.connect("wss://localhost:443")
File "C:\Program Files\Python36\lib\site-packages\websocket\_core.py", line 220, in connect
options.pop('socket', None))
File "C:\Program Files\Python36\lib\site-packages\websocket\_http.py", line 126, in connect
sock = _ssl_socket(sock, options.sslopt, hostname)
File "C:\Program Files\Python36\lib\site-packages\websocket\_http.py", line 253, in _ssl_socket
sock = _wrap_sni_socket(sock, sslopt, hostname, check_hostname)
File "C:\Program Files\Python36\lib\site-packages\websocket\_http.py", line 232, in _wrap_sni_socket
server_hostname=hostname,
File "C:\Program Files\Python36\lib\ssl.py", line 401, in wrap_socket
_context=self, _session=session)
File "C:\Program Files\Python36\lib\ssl.py", line 808, in __init__
self.do_handshake()
File "C:\Program Files\Python36\lib\ssl.py", line 1061, in do_handshake
self._sslobj.do_handshake()
File "C:\Program Files\Python36\lib\ssl.py", line 683, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
我也尝试了一个简单的http.server.HTTPServer
,但唯一的区别是,对于第一个客户端(片段 1),它不会在每次发送后打印消息,而是在我停止客户端后累积所有接收到的消息并一起打印所有消息,出现错误:代码 400,消息错误请求语法。
tl;dr 基本上,我需要的是一个很好的例子,说明如何使用 SSL 连接到安全的 HTTPS 服务器一次,然后继续发送字符串消息,直到应用程序停止。
一个小更新:
如果我这样编写客户端,它会起作用,但前提是我在每条消息后关闭并重新打开连接:
import json
import websocket, ssl
import time
ws = None
def send(msg="..."):
global ws
if ws is None:
ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE,
"ssl_version": ssl.PROTOCOL_TLSv1,
"certfile": "cert.pem",
"keyfile": "key_wopasswd.pem"})
ws.connect("wss://localhost:443")
jsonString = json.dumps({"Time":int(time.time()), "Message":msg})
ws.send(jsonString.encode('utf-8'))
ws.close()
ws = None
########################
i = 0
while i < 10:
i = i + 1
send("i = %d" % i)
解决方案
推荐阅读
- java - 如何使用 JsonFormat 装饰通用类型字段
- android - 订购集合参考火灾
- java - 尽管没有在任何地方清除,但构造函数中的 ArrayList 分配的数据正在丢失其数据
- reactjs - 从 Facebook API React 获取数据
- angular - 在 Angular 9 中的 Mapbox 地图上添加多边形
- android - 未解决的参考:asLiveData 同时将 Flow 转换为 LiveData
- javascript - Stripe Connect form.dataset 未通过 API 密钥
- flask-login - Flask 登录 - 使用 Firebase
- jquery - 在不使用 .execCommand() 的情况下缩进 contenteditable div
- r - 在 R 中使用“扫帚”提取模型样本大小