Utilizzo della compressione websocket con uWebSockets.js e Websocket-Sharp


11

Abbiamo un gioco mobile che utilizza websocket per le connessioni. Il server è un'app Node.js che utilizza la libreria uWebSockets.js e il client è un'app Unity che utilizza la libreria Websocket-Sharp . Entrambi giocano bene insieme e non abbiamo riscontrato problemi con loro.

Recentemente abbiamo voluto abilitare la compressione del websocket . Entrambe le librerie hanno dichiarato di supportare l'estensione di compressione per messaggio, ma sembra che ci sia qualcosa di incompatibile con loro. Perché quando configuriamo l'uso della compressione, la connessione al websocket si chiude immediatamente in stretta di mano.

Abbiamo anche testato il client con la libreria ws ed è fornito un esempio per la compressione con lo stesso risultato. Abbiamo provato ad armeggiare con le opzioni di compressione ws e abbiamo scoperto che quando commentiamo l'opzione serverMaxWindowBits (il valore predefinito è negoziato), la connessione potrebbe essere stabilita e l'invio e la ricezione di messaggi funziona senza problemi. Abbiamo anche chiesto informazioni sul controllo di serverMaxWindowBits in uWebsocket.

L'ultima cosa che abbiamo provato è stata la connessione di un server uWS minimo e di un client nitido. Ecco il codice per il server:

const uWS = require('uWebSockets.js');
const port = 5001;

const app = uWS.App({
    }).ws('/*', {
        /* Options */
        compression: 1, // Setting shared compression method
        maxPayloadLength: 4 * 1024,
        idleTimeout: 1000,
        /* Handlers */
        open: (ws, req) => {
            console.log('A WebSocket connected via URL: ' + req.getUrl() + '!');
        },
        message: (ws, message, isBinary) => {
            /* echo every message received */
            let ok = ws.send(message, isBinary);
        },
        drain: (ws) => {
            console.log('WebSocket backpressure: ' + ws.getBufferedAmount());
        },
        close: (ws, code, message) => {
            console.log('WebSocket closed');
        }
    }).any('/*', (res, req) => {
        res.end('Nothing to see here!');
    }).listen(port, (token) => {
        if (token) {
            console.log('Listening to port ' + port);
        } else {
            console.log('Failed to listen to port ' + port);
        }
    });

Ecco il codice client:

using System;
using WebSocketSharp;

namespace Example
{
  public class Program
  {
    public static void Main (string[] args)
    {
      using (var ws = new WebSocket ("ws://localhost:5001")) {
        ws.OnMessage += (sender, e) =>
            Console.WriteLine ("server says: " + e.Data);

        ws.Compression = CompressionMethod.Deflate; // Turning on compression
        ws.Connect ();

        ws.Send ("{\"comm\":\"example\"}");
        Console.ReadKey (true);
      }
    }
  }
}

Quando abbiamo eseguito il server e il client, il client emette il seguente errore:

Errore | WebSocket.checkHandshakeResponse | Il server non ha inviato indietro 'server_no_context_takeover'. Fatal | WebSocket.doHandshake | Include un'intestazione Sec-WebSocket-Extensions non valida.

Sembrava che il client si aspettasse un'intestazione server_no_context_takeover e non ne avesse ricevuta una. Abbiamo esaminato l' origine uWebsockets (parte C ++ del modulo uWebsockets.js) e trovato una condizione commentata per l'invio di intestazione server_no_context_takeover. Quindi abbiamo decommentato la condizione e creato uWebsockets.js e testato di nuovo per riscontrare il seguente errore nel client:

WebSocketSharp.WebSocketException: l'intestazione di un frame non può essere letta dal flusso.

Qualche suggerimento per far lavorare insieme queste due librerie?


Non sono sicuro che aiuti, ma socket.io si comprime per impostazione predefinita. So che il miglior HTTP 2 ha un buon supporto per socket.io - websocket.
Samuel G

@SamuelG Grazie, ma l'utilizzo di socket.io non è un'opzione perché attualmente stiamo gestendo 5k + connessioni simultanee con risorse minime.
Koorosh Pasokhi,

@KooroshPasokhi che cosa ha concluso il tuo ragionamento sul fatto che socket.io non sarebbe in grado di gestire il tuo carico o richiede molte risorse? Mi piacerebbe saperne di più sui tuoi test.
Samuel G,

@SamuelG I commenti non sono per discussioni, ma diciamo che i motivi principali sono il focus di socket.io non è la prestazione e non abbiamo bisogno di astrazioni di livello superiore in socket.io.
Koorosh Pasokhi il

Risposte:


3

Aggiornamento: in base alla mia lettura del codice uWebSockets.js, è necessario apportare modifiche per abilitare tutti i parametri websocket-sharpnecessari per abilitare la compressione. In Vertx, un server Java ad alte prestazioni, le seguenti impostazioni funzionano con Unity compatibile websocket-sharpper la compressione:

vertx.createHttpServer(new HttpServerOptions()
                .setMaxWebsocketFrameSize(65536)
                .setWebsocketAllowServerNoContext(true)
                .setWebsocketPreferredClientNoContext(true)
                .setMaxWebsocketMessageSize(100 * 65536)
                .setPerFrameWebsocketCompressionSupported(true)
                .setPerMessageWebsocketCompressionSupported(true)
                .setCompressionSupported(true));

In precedenza:

L'errore è reale, websocket-sharpsupporta solo permessage-deflateuse DEDICATED_COMPRESSOR( compression: 2) invece.


Sfortunatamente l'impostazione del metodo di compressione su 2 non ha modificato il messaggio di errore :(
Koorosh Pasokhi il

Quindi c'è qualche problema di fondo con uWebSocket. Uso i websocket vertx di Java con compressione con WebSocketSharp nel client che ha più campi di configurazione e funziona.
DoctorPangloss,

Forse prova a creare un test direttamente in uWebSockets.js che riproduca il comportamento del WebSocket.csrifiuto dell'intestazione? DEDICATED_COMPRESSORdovrebbe davvero funzionare!
DoctorPangloss,

Quale test intendi? L'architettura di uWebSockets.js è un po 'complicata. Ha tre livelli scritti in JS, C ++ e C, il che rende difficile il debug.
Koorosh Pasokhi l'

Intendo creare un test nella directory del progetto uWebSockets.js che riproduce la stretta di mano di websocket-sharp, che potresti scoprire collegandola a un server conforme e vedendo cosa succede?
DoctorPangloss,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.