Tenemos un juego móvil que usa websocket para las conexiones. El servidor es una aplicación Node.js que usa la biblioteca uWebSockets.js y el cliente es una aplicación Unity que usa la biblioteca Websocket-Sharp . Ambos juegan bien juntos y no hemos encontrado un problema con ellos.
Recientemente queríamos habilitar la compresión websocket . Ambas bibliotecas declararon que son compatibles con la extensión de compresión por mensaje, pero parece que hay algo incompatible con ellas. Porque cuando configuramos para usar la compresión, la conexión websocket se cierra inmediatamente en el protocolo de enlace.
También probamos el cliente con la biblioteca ws y se proporciona un ejemplo para la compresión con el mismo resultado. Intentamos jugar con las opciones de compresión de ws y descubrimos que cuando comentamos la opción serverMaxWindowBits (por defecto es el valor negociado) la conexión podría establecerse y el envío y recepción de mensajes funciona sin problemas. También preguntamos sobre el control de serverMaxWindowBits en uWebsockets.
Lo último que intentamos fue conectar un servidor uWS mínimo y un cliente websocket. Aquí está el código para el servidor:
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);
}
});
Aquí está el código del cliente:
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);
}
}
}
}
Cuando ejecutamos el servidor y el cliente, el cliente emite el siguiente error:
Error | WebSocket.checkHandshakeResponse | El servidor no ha devuelto 'server_no_context_takeover'. Fatal | WebSocket.doHandshake | Incluye un encabezado Sec-WebSocket-Extensions no válido.
Parecía que el cliente esperaba el encabezado server_no_context_takeover y no recibió uno. Revisamos la fuente de uWebsockets (parte C ++ del módulo uWebsockets.js) y encontramos una condición comentada para devolver el encabezado server_no_context_takeover. Así que descomentamos la condición y creamos uWebsockets.js y probamos nuevamente para encontrar el siguiente error en el cliente:
WebSocketSharp.WebSocketException: el encabezado de un marco no se puede leer desde la secuencia.
¿Alguna sugerencia para hacer que estas dos bibliotecas funcionen juntas?
Respuestas:
Actualización: según mi lectura del código
uWebSockets.js
, se necesitarían hacer cambios para habilitar todos los parámetros que sewebsocket-sharp
deben configurar para habilitar la compresión. En Vertx, un servidor Java de alto rendimiento, las siguientes configuraciones funcionan con Unitywebsocket-sharp
para compresión:Previamente:
El error es real,
websocket-sharp
solo admitepermessage-deflate
, useDEDICATED_COMPRESSOR
(compression: 2
) en su lugar.fuente
WebSocket.cs
rechazo de encabezado?DEDICATED_COMPRESSOR
realmente debería funcionar!