We have a mobile game using websocket for connections. The server is a Node.js app using uWebSockets.js library and the client is a Unity app using Websocket-Sharp library. They both play well together and we didn't have encountered an issue with them.
Recently we wanted to enable websocket compression. Both libraries stated that they support Per-message Compression extension but it seems there's something incompatible with them. Because when we configure to use compression the websocket connection closes immediately on handshake.
We also tested client with ws library and it's provided example for compression with the same result. We tried tinkering with ws compression options and found that when we comment serverMaxWindowBits option (defaults to negotiated value) the connection could be established and sending and receiving messages works without a problem. We also asked about controlling the serverMaxWindowBits in uWebsockets.
The last thing we tried was connecting a minimal uWS server and websocket-sharp client. Here is the code for the 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);
}
});
Here is the client code:
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);
}
}
}
}
When we ran the server and the client, the client emits the following error:
Error|WebSocket.checkHandshakeResponse|The server hasn't sent back 'server_no_context_takeover'. Fatal|WebSocket.doHandshake|Includes an invalid Sec-WebSocket-Extensions header.
It seemed the client expected server_no_context_takeover header and didn't received one. We reviewed uWebsockets source (C++ part of uWebsockets.js module) and found a commented condition for sending back server_no_context_takeover header. So we uncommented the condition and built uWebsockets.js and tested again to encounter the following error in the client:
WebSocketSharp.WebSocketException: The header of a frame cannot be read from the stream.
Any suggestions for making these two libraries work together?