GoでWebSocket通信をやってみる

## はじめに
クライアントとサーバーで双方向通信ができるWebSocket通信を、Goでやってみました。

## Goのコード

Go側では、gorilla/websocketパッケージを利用して、WebSocketの接続を待ち受けます。

接続を確立した後は、for文で永続的にコネクションを維持します。

サーバーからのプッシュ通信をゴールーチンを使って5秒ごとにクライアントに送信しています。

```go
package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
)

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

func echo(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Upgrade error:", err)
		return
	}
	defer conn.Close()

	for {
		messageType, message, err := conn.ReadMessage()
		if err != nil {
			log.Println("Read error:", err)
			break
		}

		log.Printf("Received: %s", message)
		err = conn.WriteMessage(messageType, []byte("Hello, Client!"))
		if err != nil {
			log.Println("Write error:", err)
			break
		}

		go func() {
			for {
				time.Sleep(5 * time.Second)
				err := conn.WriteMessage(websocket.TextMessage, []byte("From Server: push message!"))
				if err != nil {
					log.Println("Write error:", err)
					break
				}
			}
		}()
	}
}

func main() {
	http.HandleFunc("/ws", echo)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
```

## クライアント側

ブラウザにはWebSocket APIが組み込まれているので、それを利用してコネクションを作ります。

サーバー側で作ったエンドポイントを指定します。

テキストを入力して送信ボタンを押すと、サーバーにデータが送信され、サーバーから返信があれば、それを画面に表示します。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket Client</title>
</head>
<body>
    <h1>WebSocket Client</h1>
    <input type="text" id="messageInput" placeholder="Type a message...">
    <button onclick="sendMessage()">Send</button>
    <div id="messages"></div>

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

        ws.onopen = function() {
            console.log("WebSocket connection established");
        };

        ws.onmessage = function(event) {
            console.log("Message received:", event.data);
            let messages = document.getElementById('messages');
            let message = document.createElement('div');
            message.textContent = event.data;
            messages.appendChild(message);
        };

        ws.onerror = function(error) {
            console.log("WebSocket error:", error);
        };

        ws.onclose = function() {
            console.log("WebSocket connection closed");
        };

        function sendMessage() {
            let input = document.getElementById('messageInput');
            if (ws.readyState === WebSocket.OPEN) {
                ws.send(input.value);
                input.value = '';
            } else {
                console.log("WebSocket connection is not open");
            }
        }
    </script>
</body>
</html>
```

## 動かしてみる

```zsh
go run main.go
```

### クライアント側

データを送信でき、サーバーからの返信も受け取れています。

コンソールログにもその様子が出力されています。

![スクリーンショット 2024-07-05 8.43.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603224/52eaf420-56f1-23a4-b876-05c22e4aac9d.png)


### サーバー側

ちゃんと受け取れています。

```zsh
2024/07/05 08:43:04 Received: test
```