shiguredo_websocket

Crates.ioshiguredo_websocket
lib.rsshiguredo_websocket
version2026.1.0-canary.1
created_at2026-01-16 09:12:15.447679+00
updated_at2026-01-23 04:50:03.137403+00
descriptionWebSocket Library
homepagehttps://github.com/shiguredo/websocket-rs
repositoryhttps://github.com/shiguredo/websocket-rs
max_upload_size
id2048282
size425,667
crates.io (github:shiguredo:crates-io)

documentation

README

websocket-rs

shiguredo_websocket Documentation License

About Shiguredo's open source software

We will not respond to PRs or issues that have not been discussed on Discord. Also, Discord is only available in Japanese.

Please read https://github.com/shiguredo/oss before use.

時雨堂のオープンソースソフトウェアについて

利用前に https://github.com/shiguredo/oss をお読みください。

概要

Rust で実装された Sans I/O な WebSocket ライブラリです。

特徴

使い方

クライアント (WebSocket 接続)

use std::io::{Read, Write};
use std::net::TcpStream;
use shiguredo_websocket::{
    ClientConnectionOptions, ConnectionEvent, ConnectionOutput,
    RandomSource, WebSocketClientConnection, Timestamp,
};

// 乱数ソースの実装
struct SecureRandom;

impl RandomSource for SecureRandom {
    fn masking_key(&mut self) -> [u8; 4] {
        let mut key = [0u8; 4];
        getrandom::fill(&mut key).expect("failed to generate masking key");
        key
    }

    fn nonce(&mut self) -> [u8; 16] {
        let mut nonce = [0u8; 16];
        getrandom::fill(&mut nonce).expect("failed to generate nonce");
        nonce
    }
}

// TCP ソケット接続
let mut socket = TcpStream::connect("echo.websocket.org:80")?;

// WebSocket 接続オプション
let options = ClientConnectionOptions::new("echo.websocket.org", "/");

// WebSocket 接続作成・開始
let mut ws = WebSocketClientConnection::new(options, SecureRandom);
ws.connect()?;

// HTTP Upgrade リクエスト送信
while let Some(output) = ws.poll_output() {
    if let ConnectionOutput::SendData(data) = output {
        socket.write_all(&data)?;
    }
}

// ハンドシェイクレスポンス受信
let mut buf = [0u8; 4096];
loop {
    let n = socket.read(&mut buf)?;
    ws.feed_recv_buf(&buf[..n], now())?;

    while let Some(event) = ws.poll_event() {
        match event {
            ConnectionEvent::Connected { protocol, extensions } => {
                println!("Connected! protocol={:?}", protocol);
            }
            ConnectionEvent::TextMessage(text) => {
                println!("Received: {}", text);
            }
            ConnectionEvent::BinaryMessage(data) => {
                println!("Received: {} bytes", data.len());
            }
            ConnectionEvent::Close { code, reason } => {
                println!("Closed: {:?} {}", code, reason);
                break;
            }
            _ => {}
        }
    }

    // 送信データがあれば送信
    while let Some(output) = ws.poll_output() {
        if let ConnectionOutput::SendData(data) = output {
            socket.write_all(&data)?;
        }
    }
}

サーバー (WebSocket 接続受付)

use shiguredo_websocket::{
    ConnectionEvent, ConnectionOutput, ConnectionState,
    ServerConnectionOptions, WebSocketServerConnection,
};

// WebSocketServerConnection の初期化
let options = ServerConnectionOptions::new();
let mut ws = WebSocketServerConnection::new(options);

// 受信データをフィード
// ws.feed_recv_buf(&received_data)?;

// ハンドシェイクの自動受諾
// if ws.state() == ConnectionState::Connecting {
//     ws.accept_handshake_auto()?;
// }

// イベント処理
// while let Some(event) = ws.poll_event() { ... }

// 出力処理
// while let Some(output) = ws.poll_output() { ... }

メッセージ送信 (クライアント)

use shiguredo_websocket::CloseCode;

// テキストメッセージ送信
ws.send_text("Hello, WebSocket!").unwrap();

// バイナリメッセージ送信
ws.send_binary(&[0x01, 0x02, 0x03]).unwrap();

// Ping 送信
ws.send_ping(&[], now()).unwrap();

// 接続を閉じる
ws.close(CloseCode::NORMAL, "Goodbye").unwrap();

メッセージ送信 (サーバー)

use shiguredo_websocket::CloseCode;

// テキストメッセージ送信
ws.send_text("Hello, WebSocket!").unwrap();

// バイナリメッセージ送信
ws.send_binary(&[0x01, 0x02, 0x03]).unwrap();

// Ping 送信
ws.send_ping(&[], now()).unwrap();

// 接続を閉じる
ws.close(CloseCode::NORMAL, "Goodbye").unwrap();

フレームの直接操作 (低レベル API)

use shiguredo_websocket::{Frame, FrameDecoder, Opcode};

// フレーム作成
let frame = Frame::text("Hello");
let masking_key = [0x12, 0x34, 0x56, 0x78];
let encoded = frame.encode(masking_key);

// フレームデコード
let mut decoder = FrameDecoder::new();
decoder.feed(&encoded);

while let Some(frame) = decoder.decode().unwrap() {
    match frame.opcode {
        Opcode::Text => {
            let text = String::from_utf8_lossy(&frame.payload);
            println!("Text: {}", text);
        }
        Opcode::Binary => {
            println!("Binary: {} bytes", frame.payload.len());
        }
        Opcode::Ping => {
            // Pong を返す
        }
        Opcode::Close => {
            // 接続を閉じる
        }
        _ => {}
    }
}

WebSocket

このライブラリが対応している WebSocket の仕組みです。

フレーム

  • テキストフレーム / バイナリフレーム
  • 制御フレーム (Ping, Pong, Close)
  • フラグメンテーション (継続フレーム)
  • マスキング (クライアント→サーバー)

ハンドシェイク

  • HTTP/1.1 Upgrade リクエスト/レスポンス
  • Sec-WebSocket-Key / Sec-WebSocket-Accept の検証
  • サブプロトコルネゴシエーション (Sec-WebSocket-Protocol)
  • 拡張ネゴシエーション (Sec-WebSocket-Extensions)

拡張

  • permessage-deflate (RFC 7692)
    • server_no_context_takeover
    • client_no_context_takeover
    • server_max_window_bits
    • client_max_window_bits

接続管理

  • 自動 Ping/Pong 応答
  • 定期的な Ping 送信 (設定可能)
  • Close ハンドシェイク
  • 状態管理 (Connecting, Connected, Closing, Closed)

セキュリティ

  • マスキングキーの検証
  • フレームサイズ制限
  • UTF-8 検証 (テキストメッセージ)

制限 (DoS 対策)

デフォルト値:

  • 最大フレームペイロードサイズ: 64MB
  • 最大メッセージサイズ: 64MB

ClientConnectionOptions / ServerConnectionOptions で各制限値をカスタマイズ可能です。

サンプル

サンプルは TokioRustls を利用しています。引数のライブラリには noargs を利用しています。

websocket_client

WS/WSS クライアントの例です。

cargo run -p websocket_client -- wss://localhost:8443/
cargo run -p websocket_client -- ws://localhost:8080/
cargo run -p websocket_client -- wss://localhost:8443/ --insecure

オプション:

  • <URL>: 接続先 URL (ws:// または wss://)
  • --insecure: 自己署名証明書を許可 (WSS のみ)

機能:

  • WS/WSS リクエスト送信
  • エコーメッセージ受信
  • permessage-deflate 対応
  • rustls-platform-verifier による TLS 検証

websocket_server

WS/WSS エコーサーバーの例です。

cargo run -p websocket_server
cargo run -p websocket_server -- --tls --cert cert.pem --key key.pem

オプション:

  • -p, --port <PORT>: リッスンポート (デフォルト: 8080, TLS 有効時: 8443)
  • --tls: WSS 有効化
  • --cert <PATH>: 証明書ファイル (PEM 形式)
  • --key <PATH>: 秘密鍵ファイル (PEM 形式)

機能:

  • WS/WSS 接続受付
  • テキスト/バイナリメッセージのエコーバック
  • 自動 Pong 応答

websocket_reverse_proxy

WS/WSS リバースプロキシの例です。

# WS -> WS
cargo run -p websocket_reverse_proxy -- --upstream ws://localhost:8080/

# WS -> WSS
cargo run -p websocket_reverse_proxy -- --upstream wss://echo.websocket.org/

# WSS -> WSS (TLS 終端)
cargo run -p websocket_reverse_proxy -- --tls --cert cert.pem --key key.pem --upstream wss://echo.websocket.org/

オプション:

  • -p, --port <PORT>: リッスンポート (デフォルト: 8080, TLS 有効時: 8443)
  • -u, --upstream <URL>: 転送先 URL (ws:// または wss://)
  • --tls: フロントエンドで WSS 有効化
  • --cert <PATH>: 証明書ファイル (PEM 形式)
  • --key <PATH>: 秘密鍵ファイル (PEM 形式)
  • --insecure: アップストリームの自己署名証明書を許可
  • --debug: デバッグログを有効化

機能:

  • WS/WSS 接続の双方向プロキシ
  • テキスト/バイナリ/Ping/Close メッセージの中継
  • permessage-deflate 対応

規格書

このライブラリが準拠している RFC 一覧です。

ライセンス

Apache License 2.0

Copyright 2026-2026, Shiguredo Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Commit count: 24

cargo fmt