[ golang ] WebSocketを使ったチャット機能を実装してみる。

[ golang ] WebSocketを使ったチャット機能を実装してみる。

こんばんは、七色メガネです。

最近は参考本を読みながら、チャットアプリの開発に勤しんでいました。
しかしなんとか完成したものの、まだまだ写経止まりで完全に理解できていないかなあというのが正直なところ。

ということで今回は一度アプリを機能ごとにバラして、もう一回作ってみようと思いました。

全4回で、次のテーマごとに記事を書いていこうと思います。

  1. websocketを使ったチャット機能の実装
  2. gomniouthを使った認証機能の実装
  3. プロバイダ、あるいはローカルからの画像取得機能の実装
  4. チャットアプリの開発

1〜3は別々のパッケージで作り直そうと思っているので、最後の4で整合性が取れるかは謎です…。

 

なお、今回参考にした書籍は次のものです。

「Go言語によるWebアプリケーション開発」

参考にしましたが、今回のチャット機能は書籍の内容から少し異なるところが多々ありますので悪しからず。

チャット機能の仕様

今回実装するチャット機能は、次の仕様に基づいて開発するものとします。

  • localhost:8080 にアクセスすることでチャットルームに移動すること。
  • チャットルームとクライアントのモデルを作成すること。
  • チャットルーム・モデルでは次のことを管理すること。
    1. クライアントの入室
    2. クライアントの退室
    3. クライアントの情報
    4. ルーム内のメッセージ
  • クライアント・モデルでは次のことを管理すること。
    1. websocketへのコネクション
    2. メッセージ
    3. 所属するチャットルームの情報
  • チャットルームでは、名前とメッセージの2種類を入力するものとすること。
  • 送信したメッセージは、チャットルームに参加しているクライアントのブラウザに即時反映されること。
  • サーバからのpushの実装として、websocketを使用すること。

機能のイメージ

今回のチャット機能の処理イメージを図に起こしてみました。手書きですまない…。

まずはwebサーバを起動させます。サーバの起動と同時に、チャットルーム・モデルを生成し、localhostのルートと/roomに対してハンドラを張ります。

次にブラウザからlocalhostのルートへアクセスすると、サーバからchat.htmlが返却されチャットページが表示されます。この時html内のscriptにより、/room との間でwebsocket 通信が開始されます。

websocket通信の開始通信をサーバが受けると、相手をクライアントとしてチャットルームに保存し、サーバ側のチャット準備が全て整います。

この状態でブラウザからメッセージを送信すると、開かれたsocketへとデータが送られ、それがサーバに届き、サーバが登録されたクライアント全員へメッセージを送信し、ブラウザに届き、チャットページに表示される、という仕組みです。

実装

今回は作成するのは次のファイルです。

  • main.go
    チャットルームの作成と起動、サーバの起動。
  • chatroom.go
    チャットルームの定義。クライアント管理とメッセージ管理。
  • client.go
    クライアントの定義。メッセージの送信と受信処理。
  • handler.go
    ハンドラの実装。
  • message.go
    メッセージの仕様を定義。
  • templates/chat.html
    チャットページのHTMLファイル。

githubにソースを上げておきます。
https://github.com/NanairoMegane/chatFunc

main,go

  • localhostの8080ポートでリクエストをlistenします。
  • 起動時にチャットルームを生成し、起動させます。
  • “/” と “/room” に対してハンドラを張ります。
main.go src

chatroom.go

  • チャットルームを表す chatroom 構造体を持ちます。
  • チャットルームを生成する newRoom() を持ちます。
  • ブラウザからアクセスがあった時(html内のscriptによる /room へのアクセス)に起動する ServeHTTP() が定義されます。ここでクライアントをchatroom構造体に保存します。
  • チャットルームを起動させる run() を持ちます。ここでは無限ループで chatroom 構造体のチャネルを監視し、クライアントの入室・退室・メッセージの到達に対しての処理を行います。
chatroom.go src

client.go

  • クライアントを表す client 構造体を持ちます。
  • socketからメッセージを読み出す read() が定義されます。htmlからsocketにsendされたメッセージがここで読み出され、クライアントが保持する(所属する)chatroom の forward チャネルに送り出します。
  • socketにメッセージを書き出す write() が定義されます。chatroom のforward チャネルにメッセージが到達した時、chatroom からこの write へメッセージが転送され、各クライアントのsocketにメッセージが書き出されます。
client.go src

 

handler.go

  • ブラウザから”/” へアクセスがあった時に chat.html をサーブするためのハンドラが定義されます。
handler.go src

 

message.go

  • やりとりされるメッセージの形式を定義します。Name はユーザ名、Message はメッセージ内容でブラウザでの入力値になります。Time は処理された時刻で、サーバで処理された時間を格納します。
message.go src

templates/chat.html

  • ブラウザが “/” へアクセスした時にサーバからserveされるHTMLファイルです。
  • チャットの表示スペースと、ユーザ名とメッセージの入力欄を持ちます。
  • このページが開かれた時、script により /room に対してwebsocket通信を行いコネクションを形成します。
  • メッセージがsubmitされた時、socketに対してメッセージを送信します。
  • サーバでクライアントに対してメッセージが送信された時socketにメッセージが到達し、socketに貼られたイベントハンドラonmessageによりそれを感知し、htmlを動的に書き換えてチャットの表示スペースにメッセージの内容を反映します。
chat.html src

チャット機能の起動

ここまでのsrcを用意したら、ビルドして実行しましょう。
localhost:8080 でリクエストをlistenし始めます。

次にブラウザからアクセスを行います。
チャットの機能テストなので2つのブラウザからアクセスを行い、お互いのブラウザでチャットが行えていることを確認します。ここでは Vivaldi と GoogleChrome の2つのブラウザでテストしてみます。

 

・Vivaldi サイドでページにアクセス

・Chromeサイドでページにアクセス

・この時点でのコンソール

 

・Vivaldiサイドでメッセージ送信

 

・Chromeサイドで到達確認。及びメッセージ送信。

・Vivaldiサイドに到達を確認。及びこの時のコンソール。

一方のクライアント(ブラウザ)からメッセージがサーバに到達した時、チャットルーム・モデルに登録されているクライアント(ブラウザ)へメッセージが送信されます。今回はクライアントが二つなので、1つのメッセに対して2回の送信が行われていることが確認できますね。

 

まとめ

今回はwebsocketを使ったチャット機能を実装してみました。
この実装で学べたことは主に次のようなことです。

  • webサーバの立て方
  • ハンドラの使い方
  • websocketの利用の仕方
  • htmlへのメッセージの反映の仕方

以上です。ここまでご覧いただき、ありがとうございました!

 

参考

今回の実装は下記の書籍を参考にしています。
が、本記事での実装とは多少異なるところがあります。(主に見た目)

 

「Go言語によるWebアプリケーション開発」

golangカテゴリの最新記事