WebSocket入門 - リアルタイム通信

intermediate | 55分 で読める | 2024.12.31

公式ドキュメント

このチュートリアルで学ぶこと

  • WebSocketの基本概念
  • サーバー実装
  • クライアント実装
  • ブロードキャスト
  • ルーム機能

ポイント: WebSocketはHTTPと異なり、一度接続すると双方向のリアルタイム通信が可能です。チャット・通知・ゲームなどに最適です。

Step 1: サーバー実装

npm install ws express
// server.js
const WebSocket = require('ws');
const http = require('http');
const express = require('express');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

const clients = new Set();

wss.on('connection', (ws) => {
 clients.add(ws);
 console.log('Client connected');

 ws.on('message', (data) => {
 const message = JSON.parse(data);
 // 全クライアントにブロードキャスト
 clients.forEach(client => {
 if (client.readyState === WebSocket.OPEN) {
 client.send(JSON.stringify(message));
 }
 });
 });

 ws.on('close', () => {
 clients.delete(ws);
 console.log('Client disconnected');
 });
});

server.listen(3000, () => {
 console.log('Server running on http://localhost:3000');
});

Step 2: クライアント実装

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
 <title>Chat</title>
</head>
<body>
 <div id="messages"></div>
 <input id="input" type="text" />
 <button onclick="sendMessage()">Send</button>

 <script>
 const ws = new WebSocket('ws://localhost:3000');

 ws.onopen = () => console.log('Connected');

 ws.onmessage = (event) => {
 const message = JSON.parse(event.data);
 const div = document.createElement('div');
 div.textContent = `${message.user}: ${message.text}`;
 document.getElementById('messages').appendChild(div);
 };

 function sendMessage() {
 const input = document.getElementById('input');
 ws.send(JSON.stringify({
 user: 'User',
 text: input.value
 }));
 input.value = '';
 }
 </script>
</body>
</html>

実践メモ: Socket.ioは素のWebSocketよりも高機能で、自動再接続・フォールバック・ルーム機能を標準で提供します。本番利用ではSocket.ioが推奨です

Step 3: Socket.io版

npm install socket.io
// server.js
const { Server } = require('socket.io');
const http = require('http');

const server = http.createServer();
const io = new Server(server, {
 cors: { origin: '*' }
});

io.on('connection', (socket) => {
 console.log('User connected:', socket.id);

 socket.on('join', (room) => {
 socket.join(room);
 });

 socket.on('message', (data) => {
 io.to(data.room).emit('message', data);
 });

 socket.on('disconnect', () => {
 console.log('User disconnected');
 });
});

server.listen(3000);

Step 4: Reactクライアント

// useSocket.ts
import { useEffect, useState } from 'react';
import { io, Socket } from 'socket.io-client';

export function useSocket(url: string) {
 const [socket, setSocket] = useState<Socket | null>(null);
 const [messages, setMessages] = useState<string[]>([]);

 useEffect(() => {
 const newSocket = io(url);
 setSocket(newSocket);

 newSocket.on('message', (msg) => {
 setMessages(prev => [...prev, msg]);
 });

 return () => { newSocket.close(); };
 }, [url]);

 const sendMessage = (msg: string) => {
 socket?.emit('message', msg);
 };

 return { messages, sendMessage };
}

リアルタイム通信で設計すること

WebSocketは接続を張り続けるため、通常のHTTP APIよりも接続管理が重要になります。メッセージを送る処理だけでなく、接続開始、切断、再接続、認証切れ、重複送信をどう扱うかを決めておく必要があります。

チャットや通知では、送ったメッセージが必ず届くとは限りません。ネットワークが切れた場合に再送するのか、履歴APIで取り直すのか、既読や順序をどこで保証するのかを整理すると、実装後の不具合を減らせます。

実装時の確認

  • 接続が切れたときに再接続するか
  • 同じメッセージが二重表示されないか
  • 認証が切れた接続を閉じられるか
  • サーバー再起動時にクライアントが復旧できるか

まとめ

注意: WebSocket接続はメモリを消費し続けるため、不要になったら必ずclose()で切断してください。リスナーのクリーンアップも忘れずに。

WebSocketで双方向リアルタイム通信を実現できます。Socket.ioを使えばフォールバックや再接続も自動処理されます。

参考リソース

← 一覧に戻る
PR
PR
PR
PR