大家好,很高興又見面了,我是"進階前端進階",由我帶着大家一起關注前端前沿、深入前端底層技術,大家一起進步,也歡迎大家關注、點贊、收藏、轉發!
進階前端進階
今天給大家帶來的主題是最近因為 Bun運作時而大火的 µWebSockets,話不多說,直接進入正題。
1.什麼是µWebSockets
µWebSockets是簡單、安全且符合标準的 Web 伺服器,适用于要求最苛刻的應用程式。
圖檔來自:https://morioh.com/p/d76ceffb2a17
µWebSockets具有以下特點:
- 優化的安全性:µWebSockets 針對速度和記憶體占用進行了精心優化,其速度足以執行加密的 TLS 1.3 消息傳遞,甚至比大多數替代伺服器執行未加密的明文消息傳遞的速度還要快。
- 快速編寫腳本:µWebSockets 完全用 C 和 C++ 編寫,但與 Node.js 後端無縫內建。 這允許使用廣泛的能力快速編寫功能強大的應用程式的腳本。 除了支援與 Node.js 內建之外,開發者還可以使用 Bun,其中 µWebSockets 是 Bun 運作時内置 Web 伺服器。
- 大量實戰證明:從 2016 年以來,µWebSockets一直完全符合标準,擁有完美的 Autobahn|Testsuite 分數。µWebSockets 為世界上許多最大的加密貨币交易所提供支援,每天處理數十億美元的交易量。
- 開箱即用:圍繞具有通配符和參數支援的友善 URL 路由器設計 ,與高效的 WebSockets 釋出/訂閱功能相結合。 µWebSockets 應該是任何具有高要求的實時 Web 項目的明智選擇。
目前 µWebSockets 在Github上通過 Apache-2.0 協定開源,有超過 15.5k 的star、1.7k的fork、代碼貢獻者100+,是一個值得關注的前端開源項目。
2.詳述 µWebSockets 特性
符合标準
與其他“釋出/訂閱代理”不同,µWS不推動任何特定的應用程式協定,而是僅在原始的标準 WebSockets 上運作。 開發者隻需要一個符合标準的 Web 浏覽器和一些符合标準的 JavaScript 即可與之通信。
µWebSockets也不需要或強制執行特定的用戶端庫,這與 Socket.IO 等解決方案不同,在 Socket.IO 中,開發者最終會被鎖定到一組性能糟糕的專有非标準協定。
Socket.IO 支援實時雙向基于事件的通信,由一個 Node.js 伺服器和一個用于浏覽器(或 Node.js 用戶端)的 Javascript 用戶端庫組成。 支援衆多語言實作,包括:Java、C++、Swift、Dart、Python、.NET、Rust。具有諸多優秀特性,比如:可靠、自動重新連接配接、斷開檢測、二進制支援、跨浏覽器、多路複用支援等等。
高性能
µWebSockets實作僅包含頭檔案 C++17,跨平台并編譯為幾千位元組的微小二進制檔案,底層依賴于 µSockets。
µSockets 是 µWebSockets 使用的非阻塞、每個 CPU 一個線程(thread-per-CPU)的基礎庫。 µSockets 提供優化的網絡,在所有支援的傳輸、事件循環和平台上使用相同的不透明 API程式設計接口(QUIC 正在開發中,io_uring 也是如此)。
借助于 µSockets,µWebSockets 應用程式可以在諸多平台上運作,不需要任何代碼更改或特殊的執行路徑。進而實作通過 TCP 傳輸資料與通過 QUIC 傳輸資料一樣簡單。
µWebSockets的高性能
在性能方面,µWebSockets 相對于其他解決方案具有明顯的優勢,使用 SSL 的 µWS 明顯優于運作非 SSL 的最快 Golang 伺服器的消息案例。 從某種意義上說,開發者可以免費獲得 SSL(證明對于每條消息最多 4 kB 的消息傳遞是正确的)。
µWebSockets 公開展示了單個 Raspberry Pi 4 可以同時為超過 10 萬個非常活躍的 TLS 1.3 WebSockets 提供服務的詳細案例,并且具有出色的穩定性。 這對于絕大多數替代解決方案來說是完全不可能的。 在如此有限的硬體上,大多數解決方案都會變得不可靠。 同時,µWebSockets 與 Node.js 相比,支援每秒提供 12 倍的 HTTP 請求。
Raspberry Pi 4是一款單闆計算機,所謂單闆機是具有計算機功能的微型計算機,印刷闆上有中央處理機、記憶體儲器、外圍裝置、接口等主要部件。
使用簡單
µWebSockets的另一個目标是極簡主義、簡單和優雅。 它遵循類似 ExpressJS 的界面,開發者可以在其中将回調附加到不同的 URL 路由, 這樣就可以在幾行代碼中輕松建構完整的 REST/WebSocket 服務。
心跳逾時、背壓處理等繁瑣的邏輯由庫本身高效、輕松處理。 同時,該項目是異步的,并且在一個線程本地運作。 開發者将其擴充為單獨的線程,就像 Node.js 擴充為單獨的程序一樣(也就是說,實作隻看到一個線程并且不是線程安全的)。 但是,如果确實需要,有一些簡單的方法可以通過異步委托進行線程處理。
編譯
µWebSockets 可以在任何平台上編譯, 但是正如前面所說它依賴于 µSockets,即在 Linux、Windows 和 macOS 上運作的特定于平台的 C 代碼。
µSockets 有一些編譯标志,但 µSockets 和 µWebSockets 标志之間有以下共同點:
- LIBUS_NO_SSL :為 uSockets 和 uWebSockets 建構禁用 OpenSSL 依賴/功能
- UWS_NO_ZLIB : 為 uWebSockets 禁用 Zlib 依賴/功能
3.µWebSockets 如何用于Node.js環境
µWebSockets.js 是 Node.js 中的 Web 伺服器實作,它在高度優化的 C++ 中重新實作事件、網絡、加密、Web 協定、路由和釋出/訂閱。 是以,µWebSockets.js 可以為 Node.js 提供 Web 服務,是 Fastify 的 8.5 倍,至少是 Socket.IO 的 10 倍, µWebSockets.js 也是 Bun 内置的 Web 伺服器。
µWebSockets.js的目标是用符合标準、輕量級和高性能的堆棧完全取代 ExpressJS 和 Socket.io。 目前 µWebSockets.js 确實在性能上也完勝其他更流行的庫,比如: websockets 和 ws。
下面是µWebSockets.js的使用示例:
/* Non-SSL is simply App() */
require('uWebSockets.js').SSLApp({
/* 這裡支援衆多的SSL配置 */
key_file_name: 'misc/key.pem',
cert_file_name: 'misc/cert.pem',
}).ws('/*', {
/* 有許多常見的幫助功能 */
idleTimeout: 32,
maxBackpressure: 1024,
maxPayloadLength: 512,
compression: DEDICATED_COMPRESSOR_3KB,
/* 為簡潔起見,跳過其他事件,比如:upgrade, open, ping, pong, close */
message: (ws, message, isBinary) => {
/* 也可以執行 app.publish('sensors/home/temperature', '22C') 類型的釋出/訂閱*/
/* 在這裡可以回顯消息,還可以壓縮*/
let ok = ws.send(message, isBinary, true);
}
}).get('/*', (res, req) => {
/* It does Http as well */
res.writeStatus('200 OK').writeHeader('IsExample', 'Yes').end('Hello there!');
}).listen(9001, (listenSocket) => {
if (listenSocket) {
console.log('Listening to port 9001');
}
});
3.1 編譯 µWebSockets 二進制檔案
在大多數情況下,開發者可以直接執行 npm install uNetworking/uWebSockets.js#v17.3.0 并直接擷取預建構的二進制檔案。 但是,如果遇到 µWS 版本與 Node.js 建構不相容的問題,則必須在目标機器上編譯二進制檔案:
// 克隆倉庫 w/ submodules
git clone --recursive https://github.com/uNetworking/uWebSockets.js.git
//Cd 到指定目錄
cd uWebSockets.js
// build編譯
make
如果要部署到 CentOS 伺服器上,則必須在 build.c 中将編譯器從 clang 更改為 gcc:
// Change from
build("clang", "clang++", "-static-libstdc++ -static-libgcc -s", OS, "x64");
// To this
build("gcc", "g++", "-static-libstdc++ -static-libgcc -s", OS, "x64");
3.2 µWebSockets用于伺服器端
初始設定
下面從一個簡單的模闆開始:
// server.js
const uWS = require('./uws.js');
const { uuid } = require('uuidv4');
const port = 7777;
let SOCKETS = [];
const app = uWS.App()
.ws('/ws', {
// config
compression: 0,
maxPayloadLength: 16 * 1024 * 1024,
idleTimeout: 60,
open: (ws, req) => {
// this handler is called when a client opens a ws connection with the server
},
message: ws => {
// called when a client sends a message
},
close: (ws, code, message) => {
// called when a ws connection is closed
}
}).listen(port, token => {
token ?
console.log(`Listening to port ${port}`) :
console.log(`Failed to listen to port ${port}`);
});
如果運作 node server.js 則可以在 ws://127.0.0.1:7777/ws 開始接收傳入的 ws 連接配接。
4.本文總結
本文主要和大家介紹一個最近因為Bun運作時而大火的µWebSockets。相信通過本文的閱讀,大家對 µWebSockets 會有一個初步的了解。
因為篇幅有限,文章并沒有過多展開,如果有興趣,可以在我的首頁繼續閱讀,同時文末的參考資料提供了大量優秀文檔以供學習。最後,歡迎大家點贊、評論、轉發、收藏!
參考資料
https://github.com/uNetworking/uWebSockets/blob/master/misc/READMORE.md
https://github.com/uNetworking/uWebSockets.js/
https://edisonchee.com/writing/intro-to-%C2%B5websockets.js/
https://github.com/socketio/socket.io
https://github.com/uNetworking/uSockets
https://morioh.com/p/d76ceffb2a17
https://ably.com/blog/whats-new-in-socketio-4