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 はローカルで開いても通信できる