【Go】チャットっぽいものでWebSocketを実装

プログラミング

WebSocketを触る機会があったのでGo言語で簡単にWebSocketを実装して動作を検証してみました。

WebSocketは、Webアプリケーションでリアルタイム通信を実現するためのプロトコルです。

WebSocketを使用することで、サーバーとクライアント間で双方向通信を行うことができます。

この記事では、Go言語を使用してWebSocketを実装する方法をチャットっぽいものを例にして紹介します。

WebSocketとは

WebSocketは、クライアントとサーバ間でのリアルタイム通信を実現するためのプロトコルです。

WebSocketを使用することで、Webアプリケーションはサーバからのイベントを受け取ったりサーバにデータを送信したりすることができます。

サーバとクライアント間で双方向通信を行うことができるため、リアルタイムでのデータの送受信が可能です。

また、WebSocketは長期間接続を維持することができるためクライアントとサーバ間でのやり取りを継続することができます。

現在ではさまざまなタイプのリアルタイムアプリケーション(例えば、オンラインゲームやチャットアプリケーション)で広く使われています。

WebSocket API (WebSockets) - Web API | MDN
WebSocket API は、ユーザーのブラウザーとサーバー間で対話的な通信セッションを開くことができる先進技術です。この API によって、サーバーにメッセージを送信したり、応答をサーバーにポーリングすることなく、イベント駆動型のレスポンスを受信したりすることができます。

WebSocketのクライアント側

必要箇所だけピックアップするのでソースコード全体はこちらから↓

GitHub - ryofutebol/go-websocket-test
Contribute to ryofutebol/go-websocket-test development by creating an account on GitHub.

まずはサーバーからメッセージを受け取るところから見ていきます。

window.onload = function () {
    socket = new WebSocket("ws://localhost:3000/ws");
    socket.onopen = function () {
        updateMessage("接続できました");
    };
    socket.onmessage = function (event) {
        // サーバーからメッセージを受け取る
        updateMessage(event.data);
    };
};

ページを読み込んだ際にWebSocketサーバーのURLを指定してWebSocketオブジェクトを生成します。

onopenメソッドではWebSocket接続が開始されたときに実行されます。

onmessageメソッドではサーバからのメッセージを受け取るたびに実行され、受け取ったメッセージを表示しています。

updateMessageメソッドはWebページにメッセージを表示するための関数です。

次にサーバーにメッセージを送信します。

function send() {
    let sendMessage = document.getElementById("message");
    let msg = sendMessage.value;
    if (msg == "") {
        return;
    }
    socket.send(msg);
    updateMessage(msg);
    sendMessage.value = "";
}

HTMLから送信するメッセージを取得しWebSocketオブジェクトのsendメソッドを使用して、送信するメッセージをWebSocketサーバに送信しています。

WebSocketのサーバー側

今回はgolang.org/x/net/websocketパッケージを使った方法になります。

いろいろ調べているとgorilla/websocketを使った方法もありました。

mainメソッドから見ていきます。

var broadcast = make(chan string)

func main() {
	http.HandleFunc("/", index)
	http.Handle("/ws", websocket.Handler(handleConnection))
	go handleMessages()

	// HTTPサーバーを開始して、ポート3000でリクエストを待ち受け
	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		log.Fatal(err)
	}
}

最初にブロードキャストするためのchannel宣言をしておきます。

WebSocketのルーティングを登録し、メッセージを処理するメソッドをゴルーチンで実行します。

次にhandleConnectionを見ていきます。

func handleConnection(ws *websocket.Conn) {
	defer ws.Close()

	// 初回のメッセージを送信
	err := websocket.Message.Send(ws, "こんにちは!")
	if err != nil {
		log.Fatalln(err)
	}

	clients[ws] = true
	for {
		// メッセージを受信する
		msg := ""
		err = websocket.Message.Receive(ws, &msg)
		if err != nil {
			log.Fatalln(err)
		}
		// 受け取ったメッセージをbroadcastチャネルに送る
		broadcast <- msg
	}
}

クライアントとWebSocketの接続ができたらwebsocket.Message.Sendメソッドで最初のメッセージをサーバー側から送信します。

ループの中でwebsocket.Message.Receiveメソッドを使用して、WebSocket接続から新しいメッセージを受信しています。

受信したメッセージを最初に宣言しておいたbroadcastチャンネルに送信して、他のクライアントにメッセージをブロードキャストすることができます。

最後にメッセージを処理する中身です。

func handleMessages() {
	for {
		// broadcastチャネルからメッセージを受け取る
		msg := <-broadcast
		// 接続中の全クライアントにメッセージを送る
		for client := range clients {
			// メッセージを返信する
			err := websocket.Message.Send(client, fmt.Sprintf(`%q というメッセージを受け取りました。`, msg))
			if err != nil {
				log.Fatalln(err)
			}
		}
	}
}

broadcastチャンネルからメッセージを受信し、WebSocket接続しているクライアントに対してメッセージを送信します。

これでメッセージ送信元のクライアント以外のクライアントにもメッセージが送信されます。

挙動確認

上記コードを元にlocalhost:3000にアクセスするとWebSocketが接続されていることがわかります。

ステータスコードが101でプロトコルを切り替えたと書いていますね。

WebSocketでのチャットの挙動を確認してみます。

クライアントから送ったメッセージがサーバーで受け取って返していることがわかります。

しかし、これだと普通のHTTPでも実現可能です。

別ブラウザを2つ起動して確認してみます。

ブラウザAで送信した内容がサーバーに行き、WebSocket接続しているブラウザBにも同じ内容が送信されていることがわかります。

参考

コメント

タイトルとURLをコピーしました