我有一个 Python WebSocket 服务器和一个 Node.js 客户端,但我无法实现 WebSocket 的协议握手。
Python 服务器代码
下面是一个最小的 WebSocket 服务器,它使用 Flask-Sockets
(使用了 gevent-websocket
)。文件名为 ws_server.py
:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from flask import Flask, request, Response
from flask_sockets import Sockets
app = Flask(__name__)
sockets = Sockets(app)
@sockets.route('/')
def echo_socket(ws):
# print("type request: ",type(request))
# print("dir request: ", dir(request))
print("request.headers: ", request.headers)
# print("type ws: ",type(ws))
# print("dir ws: ",dir(ws))
if hasattr(request, "Sec-Websocket-Protocol"):
print(request.headers["Sec-Websocket-Protocol"])
else:
print("INFO: No protocol specified")
if request.headers["Sec-Websocket-Protocol"] == "aProtocol":
print("INFO: protocol is OK")
else:
print("INFO: protocol not accepted: closing connection")
ws.close()
while not ws.closed:
message = ws.receive()
if message:
print("received: "+message)
ws.send(message)
if ws.closed:
print("INFO: connection has been closed")
if __name__ == "__main__":
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('', 5001), app, handler_class=WebSocketHandler)
server.serve_forever()
Node.js客户端的代码
以下是最简websocket客户端的代码,使用了websocket
库。
文件名为app.js
:
'use strict'
var WebSocketClient = require('websocket').client;
var client = new WebSocketClient();
function connectToServer(uri,protocol){
client.on('connectFailed', function (error) {
console.log('Connect Error: ' + error.toString());
});
client.on('connect', function (connection) {
console.log('WebSocket Client Connected');
connection.on('error', function (error) {
console.log("Connection Error: " + error.toString());
});
connection.on('close', function () {
console.log('echo-protocol Connection Closed');
});
connection.on('ping', () => {
connection.pong();
});
connection.on('message', function (message) {
if (message.type === 'utf8') {
console.log("Received message is: '" + message.utf8Data + "'");
}
});
console.log("sending SOMETHING");
connection.sendUTF("SOMETHING");
});
client.connect(uri, protocol);
}
const wsHostAndPort = process.env.WSHSTPRT || "ws://echo.websocket.org:80";
const wsProtocol = process.env.WSPRTCL || []; // [] for no protocol
console.log("connecting to: ",wsHostAndPort,"with protocol",wsProtocol);
connectToServer(wsHostAndPort,wsProtocol);
作为客户端连接Node.js
启动Python WebSocket服务器:
$ python3 ws_server.py
从Node.js的ws客户端连接:
$ WSHSTPRT=ws://localhost:5001/ WSPRTCL="aProtocol" node app.js
客户端终端的输出是:
connecting to: ws://localhost:5001/ with protocol aProtocol
Connect Error: Error: Expected a Sec-WebSocket-Protocol header.
服务器终端的输出是:
request.headers: Upgrade: websocket
Connection: Upgrade
Sec-Websocket-Version: 13
Sec-Websocket-Key: +QjH5xejDI+OQZQ0OZcWEQ==
Host: localhost:5001
Sec-Websocket-Protocol: aProtocol
INFO: No protocol specified
INFO: protocol is OK
INFO: connection has been closed
我认为Python服务器需要设置一个名为"Sec-WebSocket-Protocol"
的头,头的值应该与从客户端接收到的相同。但是我不知道如何做到这一点。我已经在互联网上搜索了一些资料(主要是 flask-sockets
和gevent-websockets
论坛和问题跟踪器),但目前还没有任何进展。
我尝试了另一个简单的客户端websocat
,我像这样调用它:$ websocat ws://localhost:5001 --protocol aProtocol
我交互式地提示了一些消息,这些消息由Python服务器正确地回显。我认为这是因为websocat
(与nodejs' websocket
不同)在与服务器进行握手时不需要"Sec-WebSocket-Protocol header"。
但我需要使用期望此标头的nodejs客户端。因此我的问题是:如何在Python服务器握手响应中加入"Sec-WebSocket-Protocol"
头?