GoでWebSocketを実装する[リアルタイム通信の実装方法について]

## はじめに

WebSocketは、リアルタイム通信を実現するための技術です。  
通常のHTTP通信では、クライアントがリクエストを送るたびにサーバーが応答する方式ですが、WebSocketはサーバーとクライアントの間で常に接続を維持し、双方向通信が可能です。

Goには、標準のnet/httpパッケージではWebSocketをサポートしていませんが、サードパーティのライブラリ「github.com/gorilla/websocket」を使うことで、簡単にWebSocketを実装できます。

今回は、GoでWebSocketサーバーを実装する方法を、基本から実践まで初心者向けにわかりやすく解説していこうと思います。

**対象読者**
- Goでリアルタイム通信を実装してみたい方
- HTTP通信ではなくWebSocketを使った効率的な通信を学びたい方
- GoでWebSocketサーバーを構築し、クライアントと連携したい方

**目次**
1. そもそもWebSocketとは？
   - HTTP通信との違い
   - WebSocketの仕組み
2. GoでWebSocketを実装する準備
   - 必要なライブラリのインストール
   - gorilla/websocketの導入
3. WebSocketサーバーの実装
   - WebSocketのハンドシェイク処理
   - クライアントからのメッセージ受信 & 送信
   - 複数のクライアントを管理する
4. WebSocketクライアントの実装（JavaScript）
5. 実践：シンプルなチャットアプリの作成

---

## 1. そもそもWebSocketとは？

#### **1.1 HTTP通信との違い**

| 項目 | HTTP 通信 | WebSocket 通信 |
|------|----------|---------------|
| **接続方式** | リクエスト & レスポンス方式 | 常時接続（双方向通信） |
| **通信速度** | 低速（都度リクエスト） | 高速（リアルタイム） |
| **サーバープッシュ** | 不可 | 可能 |

通常のHTTPは、リクエストを送るたびに接続を開いて閉じますが、WebSocketは接続を開いたままにし、サーバーとクライアントが自由にデータをやり取りできます。

#### **1.2 WebSocketの仕組み**

1. クライアントがWebSocket接続を要求
2. サーバーがWebSocket接続を承認（ハンドシェイク）
3. 接続が確立され、双方向通信が可能
4. クライアントとサーバーが自由にデータを送受信

---

## 2. GoでWebSocketを実装する準備

#### **2.1 必要なライブラリのインストール**

WebSocketをGoで実装するには、gorilla/websocketライブラリを使用します。

以下のコマンドでインストールしましょう。

```sh
go get -u github.com/gorilla/websocket
```

---

## 3. WebSocketサーバーの実装

#### **3.1 WebSocketのハンドシェイク処理**

**main.go**
```go
package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println("WebSocket connection failed:", err)
        return
    }
    defer conn.Close()

    for {
        messageType, msg, err := conn.ReadMessage()
        if err != nil {
            fmt.Println("Read error:", err)
            break
        }
        fmt.Printf("Received: %s\n", msg)
        conn.WriteMessage(messageType, msg) // 受信したメッセージをそのまま返す
    }
}

func main() {
    http.HandleFunc("/ws", handleWebSocket)
    fmt.Println("WebSocket server started on ws://localhost:8080/ws")
    http.ListenAndServe(":8080", nil)
}
```

#### **3.2 WebSocketクライアントの実装（JavaScript）**

**index.html**
```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>WebSocket Chat</title>
</head>
<body>
    <input id="message" type="text" placeholder="メッセージを入力">
    <button onclick="sendMessage()">送信</button>
    <ul id="chat"></ul>

    <script>
        const ws = new WebSocket("ws://localhost:8080/ws");

        ws.onmessage = (event) => {
            const msgList = document.getElementById("chat");
            const li = document.createElement("li");
            li.textContent = event.data;
            msgList.appendChild(li);
        };

        function sendMessage() {
            const input = document.getElementById("message");
            ws.send(input.value);
            input.value = "";
        }
    </script>
</body>
</html>
```

---

## 4. 実践：シンプルなチャットアプリの作成

このコードを実行すると、リアルタイムチャットアプリが動作します。

1. `go run main.go` でサーバーを起動
2. `index.html` をブラウザで開く
3. メッセージを入力して送信すると、WebSocket経由でサーバーに送られ、全クライアントに反映される

---

## まとめ

| 項目 | 説明 |
|------|------|
| **WebSocket** | クライアントとサーバーの双方向通信を可能にする技術 |
| **gorilla/websocket** | GoでWebSocketを実装するためのライブラリ |
| **ハンドシェイク処理** | クライアントの接続要求を承認し、WebSocket接続を確立するプロセス |
| **リアルタイムチャット** | WebSocket を使ってメッセージの送受信を即時反映 |

これでリアルタイムチャットは簡単に再現できます！
発展系として、WebSocketを活用した通知システムだったり、Redisを使ったスケーラブルなWebSocketサーバーの構築もできますので是非試してみてください！