Как установить заголовок «Sec-WebSocket-Protocol» в ответе рукопожатия сервера python websocket? - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть сервер веб-сокета Python и клиент nodejs, и я не могу реализовать протокольное рукопожатие websocket .

Код сервера Python

Следующий минимальный сервер веб-сокетов использует 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()

Код клиента nodejs

Следующий минимальный клиент 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);

Соединение с nodejs как клиент

Запустить python ws сервер:

$ python3 ws_server.py

Соединение с nodejs ws client:

$ 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" в рукопожатии с сервер.

Но мне нужно использовать клиент nodejs, который ожидает заголовок. Итак, мой вопрос: как я могу включить "Sec-WebSocket-Protocol" заголовок в ответе рукопожатия сервера Python?

...