Mamy grę mobilną używającą websocket do połączeń. Serwer to aplikacja Node.js korzystająca z biblioteki uWebSockets.js, a klient to aplikacja Unity korzystająca z biblioteki Websocket-Sharp . Obaj grają dobrze razem i nie mieliśmy z nimi problemu.
Ostatnio chcieliśmy włączyć kompresję websocket . Obie biblioteki stwierdziły, że obsługują rozszerzenie kompresji per-message, ale wygląda na to, że jest z nimi coś niezgodnego. Ponieważ gdy skonfigurujemy użycie kompresji, połączenie websocket zamyka się natychmiast po uzgadnianiu.
Przetestowaliśmy również klienta z biblioteką ws i jest to przykład kompresji z takim samym wynikiem. Próbowaliśmy majstrować przy opcjach kompresji ws i stwierdziliśmy, że kiedy komentujemy opcję serverMaxWindowBits (domyślnie jest to wynegocjowana wartość), można nawiązać połączenie, a wysyłanie i odbieranie wiadomości działa bez problemu. Zapytaliśmy również o kontrolowanie serverMaxWindowBits w uWebsockets.
Ostatnią rzeczą, jakiej próbowaliśmy, było połączenie minimalnego serwera uWS i klienta z ostrymi gniazdami internetowymi. Oto kod serwera:
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);
}
});
Oto kod klienta:
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);
}
}
}
}
Gdy uruchomiliśmy serwer i klienta, klient emituje następujący błąd:
Błąd | WebSocket.checkHandshakeResponse | Serwer nie odesłał odpowiedzi „server_no_context_takeover”. Fatal | WebSocket.doHandshake | Zawiera nieprawidłowy nagłówek Sec-WebSocket-Extensions.
Wyglądało na to, że klient oczekiwał nagłówka server_no_context_takeover i go nie otrzymał. Przeanalizowaliśmy uWebsockets źródło (C ++ część modułu uWebsockets.js) i znalazł skomentował stan wysyłania nagłówek z powrotem server_no_context_takeover. Odkomentowaliśmy więc ten warunek i zbudowaliśmy plik uWebsockets.js i ponownie przetestowaliśmy pod kątem następującego błędu w kliencie:
WebSocketSharp.WebSocketException: Nagłówka ramki nie można odczytać ze strumienia.
Jakieś sugestie, aby te dwie biblioteki ze sobą współpracowały?
Odpowiedzi:
Aktualizacja: W oparciu o mój odczyt kodu
uWebSockets.js
należy wprowadzić zmiany, aby włączyć wszystkie parametrywebsocket-sharp
wymagane do włączenia kompresji. W Vertx, wysokowydajnym serwerze Java, następujące ustawienia działają zwebsocket-sharp
kompresją zgodną z Unity :Poprzednio:
Błąd jest prawdziwy,
websocket-sharp
obsługuje tylkopermessage-deflate
, zamiast tego użyjDEDICATED_COMPRESSOR
(compression: 2
).źródło
WebSocket.cs
odrzucania nagłówka?DEDICATED_COMPRESSOR
naprawdę powinno działać!