Menggunakan kompresi websocket dengan uWebSockets.js dan Websocket-Sharp

11

Kami memiliki game seluler menggunakan websocket untuk koneksi. Server adalah aplikasi Node.js menggunakan pustaka uWebSockets.js dan klien adalah aplikasi Unity menggunakan pustaka Websocket-Sharp . Mereka berdua bermain bersama dengan baik dan kami tidak mengalami masalah dengan mereka.

Baru-baru ini kami ingin mengaktifkan kompresi websocket . Kedua perpustakaan menyatakan bahwa mereka mendukung ekstensi Kompresi Per-pesan tetapi tampaknya ada sesuatu yang tidak kompatibel dengan mereka. Karena ketika kita mengkonfigurasi untuk menggunakan kompresi, koneksi websocket segera ditutup pada jabat tangan.

Kami juga menguji klien dengan pustaka ws dan ini memberikan contoh untuk kompresi dengan hasil yang sama. Kami mencoba bermain-main dengan opsi kompresi dan menemukan bahwa ketika kami mengomentari opsi serverMaxWindowBits (default untuk nilai negosiasi) koneksi dapat dibuat dan mengirim dan menerima pesan berfungsi tanpa masalah. Kami juga bertanya tentang cara mengontrol serverMaxWindowBits di uWebsockets.

Hal terakhir yang kami coba adalah menghubungkan server uWS minimal dan klien websocket-tajam. Berikut adalah kode untuk 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);
        }
    });

Berikut adalah kode klien:

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);
      }
    }
  }
}

Ketika kami menjalankan server dan klien, klien memancarkan kesalahan berikut:

Kesalahan | WebSocket.checkHandshakeResponse | Server belum mengirim kembali 'server_no_context_takeover'. Fatal | WebSocket.doHandshake | Termasuk header Sec-WebSocket-Extensions yang tidak valid.

Tampaknya header server_no_context_takeover klien diharapkan dan tidak menerima satu. Kami meninjau sumber uWebsockets (bagian C ++ dari modul uWebsockets.js) dan menemukan kondisi yang dikomentari untuk mengirim kembali header server_no_context_takeover. Jadi kami membatalkan komentar kondisi dan membangun uWebsockets.js dan menguji lagi untuk menemukan kesalahan berikut di klien:

WebSocketSharp.WebSocketException: Header suatu frame tidak dapat dibaca dari stream.

Adakah saran untuk membuat kedua perpustakaan ini bekerja bersama?

Arash
sumber
Tidak yakin itu membantu sama sekali, tetapi socket.io melakukan kompresi secara default. Saya tahu HTTP 2 Terbaik memiliki dukungan yang cukup bagus untuk socket.io - websockets.
Samuel G
@SamuelG Terima kasih, tetapi menggunakan socket.io bukan pilihan karena kami saat ini menangani 5k + koneksi bersamaan dengan sumber daya minimum.
Koorosh Pasokhi
@KooroshPasokhi apa yang menyimpulkan alasan Anda bahwa socket.io tidak akan mampu menangani beban Anda atau sumber daya intensif? Senang mendengar lebih banyak tentang tes Anda.
Samuel G
@SamuelG Komentar bukan untuk diskusi, tetapi katakanlah alasan utama adalah fokus socket.io bukan kinerja dan kita tidak perlu abstraksi lapisan yang lebih tinggi di socket.io.
Koorosh Pasokhi

Jawaban:

3

Pembaruan: Berdasarkan pembacaan saya terhadap kode uWebSockets.js, perubahan harus dilakukan untuk mengaktifkan semua parameter yang websocket-sharpperlu diatur untuk mengaktifkan kompresi. Di Vertx, server Java berkinerja tinggi, pengaturan berikut ini berfungsi dengan Unity-compatible websocket-sharpuntuk kompresi:

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

Sebelumnya:

Kesalahan itu nyata, websocket-sharphanya mendukung permessage-deflate, gunakan DEDICATED_COMPRESSOR( compression: 2) sebagai gantinya.

DoctorPangloss
sumber
Sayangnya pengaturan metode kompresi ke 2 tidak mengubah pesan kesalahan :(
Koorosh Pasokhi
Lalu ada beberapa masalah mendasar dengan uWebSockets. Saya menggunakan websockets vertx Java dengan kompresi dengan WebSocketSharp di klien yang memiliki lebih banyak bidang konfigurasi, dan hanya berfungsi.
DoctorPangloss
Mungkin mencoba mengarang tes secara langsung di uWebSockets.js yang mereproduksi perilaku WebSocket.cspenolakan tajuk? DEDICATED_COMPRESSORbenar-benar harus bekerja!
DoctorPangloss
Apa tes yang Anda maksud? Arsitektur uWebSockets.js sedikit rumit. Ini memiliki tiga lapisan yang ditulis dalam JS, C ++ dan C, yang membuat proses debug sulit.
Koorosh Pasokhi
Maksud saya membuat tes di direktori proyek uWebSockets.js yang mereproduksi handshake websocket-sharp, yang dapat Anda temukan mungkin dengan menghubungkannya ke server yang sesuai dan melihat apa yang terjadi?
DoctorPangloss