T-CREATOR

WebSocket とは?HTTP と何が違うのかを徹底解説

WebSocket とは?HTTP と何が違うのかを徹底解説

現代のウェブ開発において、リアルタイム通信の需要はますます高まっています。チャットアプリケーション、ライブ配信、オンラインゲームなど、従来の HTTP では実現困難だった双方向通信が当たり前になりました。

そこで重要な役割を果たすのが WebSocket です。WebSocket は HTTP の制限を超えた新しい通信方式として注目されており、多くのモダンなウェブアプリケーションで活用されています。

この記事では、WebSocket と HTTP の根本的な違いについて初心者の方にもわかりやすく解説いたします。技術的な仕組みから実装例まで、具体的なコード例とともにお伝えしますので、ぜひ最後までご覧ください。

WebSocket とは

WebSocket の基本概念

WebSocket は、クライアントとサーバー間で 双方向のリアルタイム通信 を実現するプロトコルです。2011年に RFC 6455 として標準化され、現在では主要なブラウザで広くサポートされています。

従来の HTTP 通信とは異なり、一度接続が確立されると、クライアントとサーバーのどちらからでも自由にデータを送信できるのが最大の特徴です。これにより、リアルタイムな情報更新やインタラクティブなユーザー体験が可能になります。

WebSocket の動作概要を図で確認してみましょう。

mermaidsequenceDiagram
    participant C as クライアント
    participant S as サーバー
    
    C->>S: HTTP ハンドシェイク要求
    S->>C: WebSocket 接続確立
    Note over C,S: 双方向通信開始
    C->>S: メッセージ送信
    S->>C: メッセージ送信
    C->>S: メッセージ送信
    S->>C: メッセージ送信
    Note over C,S: 接続は維持される
    C->>S: 接続終了

この図からわかるように、最初の HTTP ハンドシェイク後は継続的な接続が維持され、双方向でデータのやり取りが行われます。

WebSocket の特徴と仕組み

WebSocket には以下のような優れた特徴があります。

主な特徴

#特徴説明
1双方向通信クライアントとサーバーが同時にデータを送受信可能
2低遅延接続維持によりリアルタイム性を実現
3軽量なオーバーヘッドHTTP ヘッダーが不要でデータ転送が効率的
4ブラウザサポート主要ブラウザで標準対応

WebSocket の仕組みを詳しく見ていきましょう。接続確立は HTTP から始まり、その後 WebSocket プロトコルに アップグレード される仕組みになっています。

javascript// WebSocket 接続の基本的な流れ
const ws = new WebSocket('ws://localhost:8080/socket');

// 接続が開かれた時の処理
ws.onopen = function(event) {
    console.log('WebSocket接続が開かれました');
};

// メッセージを受信した時の処理
ws.onmessage = function(event) {
    console.log('受信:', event.data);
};

この初期化コードでは、ブラウザが自動的に HTTP ハンドシェイクを行い、サーバーとの WebSocket 接続を確立します。

HTTP とは

HTTP の基本概念

HTTP(HyperText Transfer Protocol)は、1990年代初頭から使われているウェブの基盤となるプロトコルです。Tim Berners-Lee によって開発され、現在でもウェブブラウザとサーバー間の通信における 標準的な方式 として広く利用されています。

HTTP は ステートレス なプロトコルであり、クライアントからサーバーへのリクエストと、サーバーからクライアントへのレスポンスという 一方向の通信 を基本としています。

HTTP 通信の基本的な流れを図で確認してみましょう。

mermaidsequenceDiagram
    participant C as クライアント
    participant S as サーバー
    
    C->>S: HTTPリクエスト
    S->>C: HTTPレスポンス
    Note over C,S: 接続終了
    
    C->>S: 新しいHTTPリクエスト
    S->>C: HTTPレスポンス  
    Note over C,S: 接続終了

このように、HTTP では毎回新しい接続を確立し、レスポンス後に接続を終了するのが基本的な動作です。

HTTP の特徴と制限

HTTP には長年の実績による安定性がある一方で、モダンなウェブアプリケーションにおいては制限も存在します。

HTTP の主な特徴

#特徴説明
1ステートレス各リクエストは独立しており、前回の状態を記憶しない
2リクエスト・レスポンス型クライアントからの要求に対してサーバーが応答
3豊富なヘッダー情報詳細なメタデータを含む通信が可能
4キャッシュ機能効率的なデータ取得をサポート

しかし、リアルタイム通信においては以下のような制限があります。

javascript// HTTPでのデータ取得例(制限あり)
async function fetchData() {
    try {
        const response = await fetch('/api/data');
        const data = await response.json();
        console.log('データ取得:', data);
        
        // 新しいデータを取得するには再度リクエストが必要
        setTimeout(fetchData, 5000); // 5秒後に再実行
    } catch (error) {
        console.error('エラー:', error);
    }
}

このコードは ポーリング と呼ばれる手法で、定期的にサーバーにリクエストを送信してデータを取得します。しかし、この方式では無駄なリクエストが発生し、サーバーへの負荷や遅延の原因となってしまいます。

HTTP の制限点

  • サーバーからクライアントへの能動的な通信ができない
  • リアルタイム性に欠ける
  • ポーリングによる無駄なトラフィック
  • 接続確立のオーバーヘッド

WebSocket と HTTP の違い

通信方式の違い

WebSocket と HTTP の最も根本的な違いは 通信方式 にあります。この違いを理解することで、それぞれの技術をより効果的に活用できるでしょう。

以下の図で両者の通信パターンを比較してみましょう。

mermaidflowchart TD
    subgraph HTTP["HTTP通信"]
        A1[クライアント] -->|リクエスト| B1[サーバー]
        B1 -->|レスポンス| A1
        A1 -.->|接続終了| B1
    end
    
    subgraph WebSocket["WebSocket通信"]
        A2[クライアント] <-->|双方向通信| B2[サーバー]
        A2 -.->|接続維持| B2
    end

HTTP の通信方式

  • クライアントが主導するリクエスト・レスポンス型
  • 一回のやり取りで接続が終了
  • サーバーからの能動的な通信は不可能

WebSocket の通信方式

  • 双方向の同時通信が可能
  • 接続を維持し続ける
  • サーバーからクライアントへの能動的な通信が可能

データ転送の違い

データ転送においても、両者には大きな違いがあります。HTTP では毎回大きなヘッダー情報を含む必要がありますが、WebSocket ではより軽量なフレーム構造でデータを転送できます。

javascript// HTTP でのデータ送信(大きなオーバーヘッド)
const httpData = {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer token123',
        'User-Agent': 'Mozilla/5.0...',
        // その他多数のヘッダー
    },
    body: JSON.stringify({ message: 'Hello' })
};
javascript// WebSocket でのデータ送信(軽量)
ws.send(JSON.stringify({ message: 'Hello' }));

データ転送の比較

#項目HTTPWebSocket
1ヘッダーサイズ500-2000 バイト2-14 バイト
2データ形式JSON, XML, HTML などテキスト、バイナリ
3圧縮gzip, deflate拡張による圧縮対応
4フレーミングなしフレーム単位での送信

接続維持の違い

接続の維持方法は、両者の性能に大きく影響します。

javascript// HTTP: 毎回新しい接続を確立
async function sendMultipleRequests() {
    for (let i = 0; i < 10; i++) {
        await fetch('/api/data'); // 毎回新しい接続
        // 接続確立 → データ転送 → 接続終了を繰り返す
    }
}
javascript// WebSocket: 一度の接続で複数のメッセージを送信
function sendMultipleMessages() {
    const ws = new WebSocket('ws://localhost:8080');
    ws.onopen = function() {
        for (let i = 0; i < 10; i++) {
            ws.send(`Message ${i}`); // 既存の接続を利用
        }
    };
}

パフォーマンスの違い

実際のパフォーマンス比較を見てみましょう。

レスポンス時間の比較

#通信回数HTTP (ms)WebSocket (ms)改善率
11回1005050%向上
210回100010090%向上
3100回1000020098%向上

このように、通信回数が増えるほど WebSocket の優位性が明確になります。特にリアルタイムアプリケーションでは、この性能差が ユーザー体験に大きく影響 するでしょう。

WebSocket の具体的な使用例

リアルタイムチャット

チャットアプリケーションは WebSocket の最も代表的な使用例です。複数のユーザーが同時にメッセージを送受信する場面では、WebSocket の双方向通信が威力を発揮します。

javascript// チャット用 WebSocket クライアント実装
class ChatClient {
    constructor(url) {
        this.ws = new WebSocket(url);
        this.setupEventHandlers();
    }
    
    setupEventHandlers() {
        this.ws.onopen = () => {
            console.log('チャットに接続しました');
            this.joinRoom('general');
        };
        
        this.ws.onmessage = (event) => {
            const message = JSON.parse(event.data);
            this.displayMessage(message);
        };
    }
    
    sendMessage(text) {
        const message = {
            type: 'chat',
            text: text,
            timestamp: new Date().toISOString()
        };
        this.ws.send(JSON.stringify(message));
    }
    
    joinRoom(roomName) {
        const joinMessage = {
            type: 'join',
            room: roomName
        };
        this.ws.send(JSON.stringify(joinMessage));
    }
}

このチャット実装では、メッセージの送信と受信が リアルタイム で行われ、ユーザーは遅延なくコミュニケーションを取ることができます。

ライブデータ更新

株価情報やスポーツの試合結果など、頻繁に変更されるデータの配信にも WebSocket が活用されています。

javascript// ライブデータ受信クライアント
class LiveDataClient {
    constructor(url) {
        this.ws = new WebSocket(url);
        this.subscribers = new Map();
        this.setupConnection();
    }
    
    setupConnection() {
        this.ws.onmessage = (event) => {
            const data = JSON.parse(event.data);
            this.notifySubscribers(data.type, data.payload);
        };
    }
    
    subscribe(dataType, callback) {
        if (!this.subscribers.has(dataType)) {
            this.subscribers.set(dataType, []);
        }
        this.subscribers.get(dataType).push(callback);
        
        // データ配信を開始
        this.ws.send(JSON.stringify({
            action: 'subscribe',
            dataType: dataType
        }));
    }
    
    notifySubscribers(dataType, payload) {
        const callbacks = this.subscribers.get(dataType);
        if (callbacks) {
            callbacks.forEach(callback => callback(payload));
        }
    }
}

この実装により、サーバー側でデータが更新されると 即座に クライアントに通知され、最新の情報を表示できます。

オンラインゲーム

オンラインゲームでは、プレイヤー同士のリアルタイムな協調や対戦が重要です。WebSocket により、低遅延でのゲーム状態同期が実現できます。

javascript// オンラインゲーム用 WebSocket クライアント
class GameClient {
    constructor(gameUrl) {
        this.ws = new WebSocket(gameUrl);
        this.gameState = {};
        this.playerId = null;
        this.setupGameHandlers();
    }
    
    setupGameHandlers() {
        this.ws.onmessage = (event) => {
            const gameData = JSON.parse(event.data);
            
            switch (gameData.type) {
                case 'gameState':
                    this.updateGameState(gameData.state);
                    break;
                case 'playerJoined':
                    this.handlePlayerJoin(gameData.player);
                    break;
                case 'playerAction':
                    this.handlePlayerAction(gameData.action);
                    break;
            }
        };
    }
    
    sendPlayerAction(action) {
        const actionData = {
            type: 'action',
            playerId: this.playerId,
            action: action,
            timestamp: Date.now()
        };
        this.ws.send(JSON.stringify(actionData));
    }
    
    updateGameState(newState) {
        this.gameState = newState;
        this.renderGame(); // ゲーム画面を更新
    }
}

ゲームでは 数十ミリ秒の遅延 が勝敗に影響することもあるため、WebSocket の低遅延通信が重要な役割を果たします。

WebSocket 実装例

サーバーサイド実装

Node.js と ws ライブラリを使用した WebSocket サーバーの実装例をご紹介します。

javascript// 必要なモジュールをインポート
const WebSocket = require('ws');
const http = require('http');
javascript// WebSocket サーバーの作成
class WebSocketServer {
    constructor(port = 8080) {
        this.server = http.createServer();
        this.wss = new WebSocket.Server({ server: this.server });
        this.clients = new Set();
        
        this.setupServer();
        this.server.listen(port, () => {
            console.log(`WebSocket サーバーがポート ${port} で起動しました`);
        });
    }
    
    setupServer() {
        this.wss.on('connection', (ws, req) => {
            console.log('新しいクライアントが接続しました');
            this.clients.add(ws);
            
            // 接続時の処理
            this.handleConnection(ws);
            
            // メッセージ受信時の処理
            ws.on('message', (message) => {
                this.handleMessage(ws, message);
            });
            
            // 接続終了時の処理
            ws.on('close', () => {
                console.log('クライアントが切断しました');
                this.clients.delete(ws);
            });
        });
    }
}
javascript// メッセージ処理の実装
handleMessage(ws, message) {
    try {
        const data = JSON.parse(message);
        
        switch (data.type) {
            case 'chat':
                this.broadcastMessage({
                    type: 'chat',
                    text: data.text,
                    timestamp: new Date().toISOString()
                });
                break;
            case 'ping':
                ws.send(JSON.stringify({ type: 'pong' }));
                break;
            default:
                console.log('不明なメッセージタイプ:', data.type);
        }
    } catch (error) {
        console.error('メッセージ解析エラー:', error);
    }
}

broadcastMessage(message) {
    const messageString = JSON.stringify(message);
    this.clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
            client.send(messageString);
        }
    });
}

この実装により、複数のクライアントに対して 同時にメッセージを配信 できるサーバーが作成できます。

クライアントサイド実装

ブラウザ側での WebSocket クライアント実装を詳しく見ていきましょう。

javascript// WebSocket クライアントクラス
class WebSocketClient {
    constructor(url) {
        this.url = url;
        this.ws = null;
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        this.reconnectInterval = 1000;
        
        this.connect();
    }
    
    connect() {
        try {
            this.ws = new WebSocket(this.url);
            this.setupEventHandlers();
        } catch (error) {
            console.error('接続エラー:', error);
            this.handleReconnect();
        }
    }
}
javascript// イベントハンドラーの設定
setupEventHandlers() {
    this.ws.onopen = (event) => {
        console.log('WebSocket 接続が確立されました');
        this.reconnectAttempts = 0;
        this.onConnectionEstablished();
    };
    
    this.ws.onmessage = (event) => {
        try {
            const data = JSON.parse(event.data);
            this.handleReceivedMessage(data);
        } catch (error) {
            console.error('メッセージパースエラー:', error);
        }
    };
    
    this.ws.onerror = (error) => {
        console.error('WebSocket エラー:', error);
    };
    
    this.ws.onclose = (event) => {
        console.log('WebSocket 接続が閉じられました', event.code);
        this.handleReconnect();
    };
}
javascript// 再接続処理の実装
handleReconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
        this.reconnectAttempts++;
        console.log(`再接続試行 ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
        
        setTimeout(() => {
            this.connect();
        }, this.reconnectInterval * this.reconnectAttempts);
    } else {
        console.error('再接続試行回数が上限に達しました');
    }
}

この実装には 自動再接続機能 が含まれており、ネットワークの一時的な障害にも対応できます。

接続とメッセージ送受信

実際のアプリケーションでの使用例を見てみましょう。

html<!-- HTML 側の実装 -->
<div id="chat-container">
    <div id="messages"></div>
    <input type="text" id="messageInput" placeholder="メッセージを入力...">
    <button onclick="sendMessage()">送信</button>
</div>
javascript// アプリケーション側の実装
let chatClient;

function initializeChat() {
    chatClient = new WebSocketClient('ws://localhost:8080');
    
    chatClient.handleReceivedMessage = function(data) {
        switch (data.type) {
            case 'chat':
                displayMessage(data.text, data.timestamp);
                break;
            case 'pong':
                console.log('サーバーからの応答を受信');
                break;
        }
    };
}

function sendMessage() {
    const input = document.getElementById('messageInput');
    const message = input.value.trim();
    
    if (message && chatClient.ws.readyState === WebSocket.OPEN) {
        chatClient.ws.send(JSON.stringify({
            type: 'chat',
            text: message
        }));
        input.value = '';
    }
}

function displayMessage(text, timestamp) {
    const messagesDiv = document.getElementById('messages');
    const messageElement = document.createElement('div');
    messageElement.innerHTML = `
        <span class="timestamp">${new Date(timestamp).toLocaleTimeString()}</span>
        <span class="message">${text}</span>
    `;
    messagesDiv.appendChild(messageElement);
    messagesDiv.scrollTop = messagesDiv.scrollHeight;
}

この実装により、ユーザーは リアルタイム でメッセージの送受信ができるチャットアプリケーションが完成します。

まとめ

WebSocket と HTTP の違いについて、技術的な仕組みから実装例まで詳しくご説明してまいりました。

重要なポイント

  • WebSocket は双方向通信とリアルタイム性を実現する現代的なプロトコル
  • HTTP は安定性と汎用性に優れた従来型のプロトコル
  • 用途に応じた適切な技術選択が重要
  • 実装時は再接続やエラーハンドリングも考慮する

WebSocket はチャット、ライブデータ配信、オンラインゲームなどのリアルタイムアプリケーションで真価を発揮します。一方、HTTP は一般的なウェブサイトや REST API には引き続き最適な選択肢でしょう。

両者の特徴を理解し、プロジェクトの要件に最適な技術を選択することで、より良いユーザー体験を提供できるアプリケーションを開発できるはずです。

関連リンク