Express×socket.ioを使ってwebsocketで遊ぼう～第１話～

```
参考にしていただければ幸いですが、参考にして不具合等が起きた場合、保障はできませんのであしからず。
間違い等あればご教授いただけると助かります。

>> 追記(2017/07/20)
nodejs, npm のインスコ方法を記載しました。
(epelからyumインスコすると、バージョンv0.10が入るので・・・)
```

# この回のゴール
・websocket通信をsocket.ioとExpressを使用して実装
・送信したデータの共有

# 環境
Windows7
Node.js v0.10.25
* 検証環境
Opera 32
Chrome 46
FireFox 41
IE 9(検証のためにダウングレードしてた・・・)

# Node.jsのインスコ
 windowsの場合は[本家](https://nodejs.org/en/)から落とすだけです。
 コマンドプロンプト上で「node -v」と打って、バージョンが表示されればOK。
　されなければ、環境変数に追加してやってください。

 CentOSの場合は下記コマンドを打ってください。
 ※CentOS6以外の場合は一行目のepelリポジトリの参照元を変えてください

```
$ rpm -ivh http://ftp.iij.ad.jp/pub/linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
$ curl --silent --location https://rpm.nodesource.com/setup_6.x | bash -
$ yum install -y gcc gcc-c++ nodejs
```

# ベースプロジェクトの作成
　**[Express](http://expressjs.com/) とは・・・**
　　[Node.js](https://nodejs.org/en/)用のフレームワーク

## Expressのインスコ

```
sudo npm install -g express-generator
```
-g でグローバルにインストールします。

`express` コマンドが使用できればokです。

## 作業フォルダを作成

以下のような構成でフォルダを３つ用意します

```text:フォルダ構成
socketTest
├━ socket
└━ chat
```

socketフォルダ：websocketのサーバーとします
chatフォルダ：実際にチャットを行うHTMLを設置します

## socketサーバーを構築

### Expressフレームワークを設置

```shell-session:shell
$ cd socketTest/socket
$ express # expressのテンプレ構築
$ npm install # 必要なパッケージのインスコ
$ npm install socket.io # package.jsonに記述してもOKです
```


### socket.ioを扱うための準備

```shell-session:shell
$ mkdir routes/module
$ touch mod_socket.js
```

上のコマンドで作成した「mod_socket.js」というファイルにwebsocket起動用のスクリプトを書いていきます。

```js:socketTest/socket/routes/module/mod_socket.js
var http = require('http');
//サーバインスタンス作成
var server = http.createServer(function (req, res) {
        res.writeHead(200, {'Content-Type':'text/html'});
        res.end('server connected');
});
var io = require('socket.io').listen(server);

  server.listen(8888);//8888番ポートで起動

  //接続確立時の処理
  io.sockets.on('connection', function (socket) {
    // この中でデータのやり取りを行う
    console.log('connected');
  });
```

app.js内で「mod_socket/js」というファイルを読み込むようにします。
上部のvar群の一番下に追加する形でいいかもですね。

```js:socketTest/socket/app.js
// socket
var socket = require('./routes/module/mod_socket.js');
```

## Nodeサーバーの起動

ここまで来たら、Expressが動作するか確認してみましょう。

Express自体はデフォルト3000番ポートになります。
websocket自体は指定したとおり8888番を用意しているので、下記のように確認してみます。

```shell-session:shell
$ pwd
***/socketTest/socket
$ npm start
```

`npm start` で起動
ctrl + c で終了です。たまに、終了に時間がかかります

**Expressとsocket.ioの確認**

`http://localhost:3000`
![express.png](https://qiita-image-store.s3.amazonaws.com/0/45080/5a0d1267-6467-6be2-e3cf-5d86d222041c.png)
Expressの初期ページが表示されています。

`http://localhost:8888/socket.io/socket.io.js`
websocket通信用にsocket.ioで自動生成されるjsファイルです。

# 外部のHTMLからwebsocket通信

```text:フォルダ構成
socketTest
├━ socket # wsサーバー
└━ chat # こっちを使います
```

```html:socketTest/chat/index.html
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>チャットルーム</title>
	<!-- /* socket.ioのjsを読み込む */ -->
	<script type="text/javascript" src="http://localhost:8888/socket.io/socket.io.js"></script>
	<script type="text/javascript">
		var socket;
		(function(){
			// socket通信が開始される
			socket = io.connect("http://localhost:8888");
		})();
	</script>
</head>
<body>

</body>
</html>
```

成功すれば、シェルの方に「connected」というメッセージが出ていると思います。
（画像では４ブラウザで開いていたのでその分ログが出ています）

![express-shell.png](https://qiita-image-store.s3.amazonaws.com/0/45080/cefe0b93-7a82-df26-7a4d-b4dba1f78318.png)

これは、「socketTest/socket/routes/module/mod_socket.js」に記述したconsole.logの内容になります。
（一応JSなのでconsole.logでのデバッグが可能です）
外部からwebsocket通信に接続されると、mod_socket.jsファイルの `connection` を通過します。
この `connection` はsocket.ioのデフォルトで用意されているものになります。


# 外部のHTMLからメッセージを送る

**＠ポイント**
・データの送信には`emit`、受信には`on`というファンクションを使用します。
・送受信するデータはJSON形式ですが、送信時は`JSON.stringify`を使って文字列形式に変換
　受信時は`JSON.parse`を使ってJSON形式に変換してやり取りをする

```html:socketTest/socket/routes/module/mod_socket.js（L：11）
  //接続確立時の処理
  io.sockets.on('connection', function (socket) {
    // この中でデータのやり取りを行う
    // 「message」という名前で受信したデータはこの中を通る
    socket.on('message', function(d){
      // そのまま全接続先へ送信
      io.emit('receiveMessage', d);
    });
  });
```

```html:socketTest/chat/index.html[body内]
<body>
	<div>
		<textarea id="message" rows="4" cols="40"></textarea>
		<button type="button" id="send">Send</button>
	</div>
	<div>
		<ul id="messageList"></ul>
	</div>
</body>
```

```js:socketTest/chat/index.html[2つ目のscript内]
	var socket, emit;
	(function(){
		socket = io.connect("http://localhost:8888");
		emit = function (name, data){
			// json → 文字列に変換して送信する関数
			socket.emit(name, JSON.stringify(data));
		}
	})();
	window.onload = function(){
		var sendBtn = document.getElementById('send');
		var message = document.getElementById('message');
		sendBtn.addEventListener("click", function(){
			emit('message', {text: message.value});
		});
		socket.on('receiveMessage', function(d){
			var data = JSON.parse(d), // 文字列→JSON
			    li = document.createElement('li'), // liタグ作成
			    list = document.getElementById('messageList'); // ulタグの取得
			li.textContent = data.text; // liタグに値を入れる
			list.appendChild(li); // ulタグの子ノードとして作成したliタグを追加
		});
	};
```

複数ブラウザで立ち上げて、メッセージを送信するとそれぞれの画面に送信したメッセージが
どんどん表示されていくと思います。

![express-2.png](https://qiita-image-store.s3.amazonaws.com/0/45080/f8d4dfa4-5888-7b00-a625-b76b0b21bf3e.png)

今回はひとまずここまでです。