一から勉強させてください( ̄ω ̄;)

最下級エンジニアが日々の学びをアウトプットしていくだけのブログです。

expressとWebSocketで簡易チャットアプリをつくってみた

今回はexpressとWebSocketを使って簡単なチャットアプリもどきを作ってみました。


どのようなアプリケーションかというと


1、アプリを起動して、メッセージ入力画面に遷移(/echo.htmlという名前にします)

この画面は上部が送信するメッセージを入力するフォーム、下部が送信された(受信した)メッセージを順次、表示していく部分になります。
        ↓

2、サーバーとの接続が成功していると「サーバーと接続しました」という受信メッセージが表示されます。
あとは入力フォームに適当なメッセージを入力して送信ボタンを押す。
        ↓

3、2で送信したメッセージが受信メッセージ欄に表示されていく。
        ↓

4、アプリケーションを終了すると、「サーバーと接続がきれました」という受信メッセージを表示して、終了。


といった感じです!!


ちなみにgithubで作ったサンプルも公開しております!

https://github.com/danimal141/echo_app


今回、主要なコードは以下の3つになります。


・echo_server.js:サーバー側処理
・/public/echo.html:メッセージ送信フォームと受信メッセージ表示部分を記述
・/public/echo_client.js:クライアント側処理


ということで早速上記のコードを見ていきたいと思います。


1、echo_server.js

これはexpressのデフォルトであるapp.jsを少し改良しただけのものになります。

//echo_server.js

/**
  * Module dependencies.
*/

//各モジュールの参照
var express = require("express") //express
  , routes = require("./routes") //routesのindex.js
  , http = require("http")
  , path = require("path")
  , WebSocketServer = require("ws").Server;

//サーバの機能を参照するインスタンスを各変数にセット

//新しいアプリケーションを作成
var app = express()
  , httpServer = http.createServer(app)
  , wss = new WebSocketServer({server:httpServer});

//configureで環境に適したミドルウェアを割り当てる ミドルウェア=追加できる機能?
app.configure(function(){
  app.set("port", process.env.PORT || 3000);
  app.set("views", __dirname + "/views");
  app.set("view engine", "jade");
  app.use(express.favicon());
  app.use(express.logger("dev"));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, "public")));
});

app.configure("development", function(){
  app.use(express.errorHandler());
});

app.get("/", routes.index);

//websocketがクライアントに接続するとサーバーインスタンスwssにconnectionイベントが発生する
wss.on("connection", function(ws){
  console.log("established websocket connection");
  //クライアントからデータを受信するとクライアントインスタンスwsにmessageイベントが発生する
  ws.on("message", function(data, flag){
    ws.send(data, {binary: flag.binary});
  });
});


//httpServer, websocketServerを起動する
httpServer.listen(app.get("port"), function(){
  console.log("Express server listening on port" + app.get("port"));
});

まずはじめの部分ではrequireで必要なモジュールを読み込んでいます。WebSocketServerの読み込みが新たに追加している部分ですね。


次にexpress()で新しいアプリケーションを作成して変数appに代入してます。そして同時にhttpServerやWebSocketServerの準備もここで行っています。


次にapp.configureの部分ですが、こちらはサーバーを立ち上げる際のアプリケーションの設定を行う部分です。

ここで、コールバック関数のみを記述している部分と”development”という引数を指定している部分がありますが、前者はどの環境においても適用される共通の設定、後者はdevelopment環境のときにのみ適用される設定となります。

そして、configureの中でapp.set, app.useと二つのメソッドが出てきますが、
setはexpressの内部で利用する設定値の指定に、useは機能(ミドルウェア)を追加するために使用します。

ここでapp.routerというミドルウェアがありますが、これは特別なミドルウェアらしく、HTTPリクエストが到着した際にリクエストのパスとメソッドに従って対応するapp.getなどのメソッドを呼び出すらしいです。
ちなみにこれは宣言しなくても利用可能で、そのときはミドルウェア呼び出しの最後に追加されるみたいです。


app.getの部分は、localhost:3000にアクセスしたときにwelcome的なメッセージを表示する部分ですね。

wss.onの部分はWebSocketがクライアントに接続したときに発生するconnectionイベントと、クライアント側からサーバー側へメッセージを送信したときに発生するmessageイベントのコールバック処理を書いています。


そして最後にhttpserverが起動したときの処理を軽く書いておいて、サーバー側の処理は完了です。


2、echo.html
echo.htmlです。

//echo.html

<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<title>WebSocket sample1</title>
		<style type="text/css">
			body{
				color:#333;
			}
			section{
				margin-top:40px;
			}
			section:nth-of-type(2){
				border-top:1px solid #333;
				margin-top:60px;
			}
			input[type="text"]{
				float:left;
			}
			button{
				height:25px;
				vertical-align:middle;
			}
			.result{
				list-style:none;
			}

		</style>
	</head>
	<body>
		<header>
			<h1>WebSocketサンプル1</h1>
		</header>
		<section>
			<h2>送信メッセージを入力してください</h2>
			<form>
				<input type="text" size="50" name="message">
				<button type="submit">送信</button>
			</form>
		</section>

		<section>
			<h2>受信したメッセージを表示します</h2>

			<p class="result"></p>
		</section>
	<script src="echo_client.js"></script>
	</body>
</html>


こちらこんな感じです。特に書く事ないですー。


3、echo_client.js
次にクライアント側のjsです。

//echo_client.js

//DOMの取得
//querySelectorはマッチする要素のうち最初の要素を返す
var form = document.querySelector("form") 
  , input = document.querySelector("input[name=message]")
  , result = document.querySelector(".result");

//websocketサーバーへ接続準備
var ws = new WebSocket("ws://localhost:3000"); //"ws://"+location.hostでもOK

//websocketサーバーとの接続完了した場合の処理-open-

ws.addEventListener("open" , function(e){
  result.innerHTML += "「サーバーと接続しました」<br>";
},false);


//websocketサーバーからメッセージを受信-message-
ws.addEventListener("message" , function(e){
  result.innerHTML += "「" + e.data + "」<br>";
},false);


//websocketとの接続切断-close-
ws.addEventListener("close" ,  function(e){
   result.innerHTML += "「接続が切れました」<br>";
},false);


//ユーザーがメッセージを入力した時の処理-submit-
form.addEventListener("submit", function(e){
  //フォームのデフォルト動作を制御する
  e.preventDefault();
  var msg = input.value;

  if(ws){
    ws.send(msg);
    //送信したら前の入力フォームを空にする
    input.value = "";
  }
},false);

まずformタグ,メッセージを入力する inpuタグ、 そして結果を表示するpタグのDOMを取得します。

次にnew WebSocket〜の部分でWebSocketサーバーとのコネクションを生成する準備をしてます。


で、あとは以下のイベント発生時のコールバック処理を記述してやりました。


・WebSocketサーバーに接続完了→open

・WebSocketサーバーからメッセージ受信→message

・WebSocketサーバーとの接続切断→close

・ユーザーがWebSocketサーバーにメッセージ送信→submit


こんな感じで、後はnode echo_server.jsとしてやって、localhost:3000/echo.htmlにアクセスすればエコーアプリケーションを試す事ができました。


echo_server.jsのほうは最初ややこしそうと思っていたのですが、何となくでも何をやっているのかがわかれば結構直感的で理解しやすいような印象でした。


今後は前にnode.jsでつくったファイルアップロードをexpressで作り直してみたり、さらにいろいろ試してみたいと思います。


あ、ちなみに今回は以下の本を参考にさせていただきました。ありがとうございます!!

HTML5ガイドブック 増補改訂版 (Google Expert Series)

HTML5ガイドブック 増補改訂版 (Google Expert Series)

小さな事からコツコツと。