WebSokectライブラリの「ws」を使ってみた
node.jsのライブラリでWebSocketを実装しているwsを実際に使ってみた時のメモ。
実際には WebSocket チャットなサービス。
Google Chromeでしか試してない
構成
- app.js : チャットアプリ
- client.js : ターミナルからチャットするためのクライアント。ブラウザからしか使わない場合は必要ない
- index.html : ブラウザでチャットするためのhtmlファイル
「einaros/ws · GitHub 」を見る
ws のインストール
npm install ws
もしくは
npm install -g ws
やることは
- http サーバーと WebSocket サーバーを同じ port から立ち上げる
- クライアント(ブラウザ、その他)からのメッセージ送信を受け取ったら、接続している全てのクライアントにレスポンスメッセージを返す
ws では、socket.io や node-websocket-server のように 接続しているクライアント全てにメッセージを投げる broadcast が実装されていないので自前で実装する。具体的には、WebSocket が接続された時に、接続ソケットを格納する配列にpushして、メッセージを送信するときにループの中でメッセージを送信し、接続切れした時点で、そのソケットを配列から排除する という事を試している
app.js
var WebSocketServer = require('ws').Server
, fs = require('fs')
, http = require('http')
, template = 'index.html'
, server = httpServer(function (req, res) {
index(template, req, res);
})
, wSServer = new WebSocketServer({ // この段階で port 指定すると、http サーバーは ws モジュール内部のものを使うようだ
"server" : server
, "path" : '/websocket' // パス指定すると、このパスのみ生きるっぽい
})
, port = 8080
, connects = []
;
wSServer.on('connection', function (ws) {
log("WebSocketServer connected");
connects.push(ws); // 配列にソケットを格納
broadcast('connected sockets: ' + connects.length);
ws.on('message', function (message) {
log('received -' + message);
broadcast(message);
});
ws.on('close', function () {
log('stopping client send "close"');
// 接続切れのソケットを配列から除外
connects = connects.filter(function (conn, i) {
return (conn === ws) ? false : true;
});
broadcast('connected sockets: ' + connects.length);
});
});
server.listen(port);
log('Server Start on port -' + port + '- ');
function broadcast (message) {
connects.forEach(function (socket, i) {
socket.send(message);
});
}
function log (str) {
console.log((new Date).toString() + ' "' + str + '"');
}
function httpServer (onRequest) {
var _server = http.createServer();
_server.on('request', function (req, res) {
log('httpServer on request');
if (typeof onRequest === 'function') onRequest(req, res);
});
_server.on('close', function () {
log('httpServer closing');
});
return _server;
}
function index (template, req, res) {
fs.stat(template, function (err, stats) {
if (err) return _error(err);
if (! stats.isFile()) return _error('not file');
fs.readFile(template, 'utf-8', function (err, data) {
if (err) return _error(err);
res.writeHead(200, {'Content-Type' : 'text/html' });
res.write(data);
res.end();
log('raed file and pirnt: ' + template);
});
});
}
function _error (res, err) {
res.writeHead(500, {'Content-Type' : 'text/plain' });
res.end(err);
log(err);
}
client.js
var argvs = process.argv
, readline = require('readline')
, rl = readline.createInterface(process.stdin, process.stdout, null)
, WebSocket = require('ws')
, ws = new WebSocket(argvs[2] || 'ws://localhost:8080/websocket');
ws.on('open', function () {
console.log('connected');
ws.send('WebSocket connected', { mask : true});
});
ws.on('close', function () {
console.log('WebSocket disconected');
});
ws.on('message', function (data, flags) {
console.log('< ' + data);
});
rl.on('line', function (line) {
ws.send(line, {mask : true });
rl.setPrompt('> ', 2);
rl.prompt();
})
rl.on('close', function () {
console.log('hava a good day!');
process.exit(0);
});
rl.setPrompt('> ', 2);
rl.prompt();
index.html
<!doctype html>
<head>
<style>
.log {
color : #000000;
border-bottom : 1px solid #888888;
background-color : #ffffff;
}
</style>
<script>
window.addEventListener('load', function () {
var ws = new WebSocket('ws://localhost:8080/websocket')
, domResult = document.getElementById('result')
, domSend = document.getElementById('send')
, domClose = document.getElementById('close')
, textField = document.getElementById('textField')
, response = []
;
function puts (str) {
response.unshift( [ '<div class="log">', str, '</div>' ].join('') );
domResult.innerHTML = response.join('\n');
}
ws.onopen = function () {
puts('open');
};
ws.onclose = function (e) {
if (e) return puts(e);
puts('close');
};
ws.onmessage = function (e) {
puts(e.data);
};
ws.onerror = function () {
puts('ON_ERROR');
};
document.getElementById('close').addEventListener('click', function () {
ws.close();
});
document.getElementById('sendF').addEventListener('submit', function () {
if (textField.value) {
ws.send(textField.value);
textField.value = '';
textField.focus();
}
});
});
</script>
</head>
<body>
<form id="sendF" action="javascript:void(0);">
<input type="text" id="textField" />
<button id="send" type="submit">send</button><br />
<button id="close" type="button">close</button>
</form>
<div id="result"></div>
</body>
その他
- アプリ立ち上げは「node app.js」
- index.html はローカルで開いても通信できる