← レッスン一覧に戻る レッスン 14 / 28
中級 api
WebSocket
はじめに
WebSocketは、ブラウザとサーバー間のリアルタイムな双方向通信を実現します。Rust/WasmでWebSocket接続の管理、メッセージのパース、アプリケーション状態の更新を行えます — すべて型安全に。
セットアップ
[dependencies.web-sys]
version = "0.3"
features = [
"WebSocket",
"MessageEvent",
"ErrorEvent",
"CloseEvent",
"BinaryType",
"console",
]接続
use web_sys::WebSocket;
let ws = WebSocket::new("wss://echo.websocket.org")?;
// バイナリデータ用のバイナリモードを設定
ws.set_binary_type(web_sys::BinaryType::Arraybuffer);メッセージの送信
// テキストの送信
ws.send_with_str("hello")?;
// バイナリデータの送信
let data: Vec<u8> = vec![1, 2, 3, 4];
let array = js_sys::Uint8Array::new_with_length(data.len() as u32);
array.copy_from(&data);
ws.send_with_array_buffer(&array.buffer())?;メッセージの受信
use web_sys::MessageEvent;
use wasm_bindgen::closure::Closure;
let onmessage = Closure::wrap(Box::new(move |e: MessageEvent| {
// テキストメッセージ
if let Some(text) = e.data().as_string() {
log!("Text: {}", text);
}
// バイナリメッセージ
if let Ok(buf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
let array = js_sys::Uint8Array::new(&buf);
let data = array.to_vec();
log!("Binary: {} bytes", data.len());
}
}) as Box<dyn FnMut(MessageEvent)>);
ws.set_onmessage(Some(onmessage.as_ref().unchecked_ref()));
onmessage.forget();接続のライフサイクル
// 接続時
let onopen = Closure::wrap(Box::new(move || {
log!("Connected!");
}) as Box<dyn FnMut()>);
ws.set_onopen(Some(onopen.as_ref().unchecked_ref()));
onopen.forget();
// 切断時
let onclose = Closure::wrap(Box::new(move |e: web_sys::CloseEvent| {
log!("Disconnected: code={}, reason={}", e.code(), e.reason());
}) as Box<dyn FnMut(_)>);
ws.set_onclose(Some(onclose.as_ref().unchecked_ref()));
onclose.forget();
// エラー時
let onerror = Closure::wrap(Box::new(move |e: ErrorEvent| {
log!("Error: {}", e.message());
}) as Box<dyn FnMut(_)>);
ws.set_onerror(Some(onerror.as_ref().unchecked_ref()));
onerror.forget();再接続パターン
#[wasm_bindgen]
pub struct ReconnectingWs {
url: String,
ws: Option<WebSocket>,
retry_count: u32,
}
#[wasm_bindgen]
impl ReconnectingWs {
pub fn connect(&mut self) -> Result<(), JsValue> {
let ws = WebSocket::new(&self.url)?;
let url = self.url.clone();
let onclose = Closure::wrap(Box::new(move || {
// 遅延後に再接続
let window = web_sys::window().unwrap();
let url = url.clone();
let closure = Closure::once(move || {
log!("Reconnecting to {}...", url);
// 接続を再作成
});
window.set_timeout_with_callback_and_timeout_and_arguments_0(
closure.as_ref().unchecked_ref(), 3000
).unwrap();
closure.forget();
}) as Box<dyn FnMut()>);
ws.set_onclose(Some(onclose.as_ref().unchecked_ref()));
onclose.forget();
self.ws = Some(ws);
Ok(())
}
}ユースケース
| アプリケーション | Wasmを使う理由 |
|---|---|
| チャットアプリ | Rustでメッセージをパース・検証、型安全なプロトコル |
| ライブダッシュボード | ストリーミングデータ(メトリクス、ログ)を高スループットで処理 |
| マルチプレイヤーゲーム | バイナリプロトコルのパース、状態の同期 |
| 共同編集エディタ | 正確性のためにRustでOT/CRDTアルゴリズムを実装 |
試してみよう
スターターコードは、接続、送信、受信、エラーハンドリングを行うWebSocketクライアント構造体を示しています。ブラウザのWebSocket APIをクリーンなRustインターフェースでラップしています。
試してみる
チャプタークイズ
すべての問題に正解してレッスンを完了しましょう