ユーザ用ツール

サイト用ツール


pub:socket-programming-on-nodejs-howto.md

Socket programing on Node.js HOWTO

netモジュールを使った非同期なネットワークプログラミングについて解説する。netモジュールについての詳細はNode.jsを参照のこと。

  • 作成日:2012年11月30日
  • 作成者:AONO Masayuki<msyaono(at)rockos.co.jp>
  • 改訂日:2012年12月11日

ソケットプログラム解説

サーバ plcsrv.js

以下抜粋

  4 var net = require('net');
  5 var HOST = 'localhost';
  6 var PORT = 3011;
 82 var server = net.createServer(function(stream) {
 83     log({'info':'connected'});
 84         stream.on('data', function(data) {
 85             recvFrom(stream, data);
 86             });
 87         stream.on('end', function() {
 88             log({'info':'disconnected'});
 89             });
 90         });
 91 
 92 server.listen(PORT, function() {
 93         console.log('server bound');
 94         });
  • 4 netモジュールのロード
  • 82-90 ソケットサーバの生成
  • 84-86 データ受信イベント処理
  • 87-89 クライアント切断イベント処理
  • 92-94 ソケットの待ち受け

注意事項:外部からの接続

listen(port, [host])の引数hostを指定すると外部から接続できなくなるため、portのみ指定して待ち受けすること。hostが省略されると、どのアドレスに対する接続も受け入れる。

クライアント plcCoonect.js

以下抜粋

ソケットの生成

  6 var net = require('net');
  7 var PARAM = {'port':3011, 'host':'rockos'};
  8 var socket = new net.Socket();
  • 6 netモジュールのロード
  • 7 接続パラメータとしてポート番号とホストアドレスの指定
  • 8 ソケットオブジェクトを構築

イベントハンドラーの登録

非同期で発生するイベントを処理するハンドラを登録しておく。ハンドラが登録されていないイベントが発生すると例外エラーとなる。

 10 setEvent(socket);

 30 function setEvent(s) {
 31     s.on('data',   /* some data received */
 32             function(data) {
 33             log({'info':'received: ' + data});
 34             });
 35 
 36     s.on('end',        /* disconnection */
 37             function() {
 38             log({'info':'disconnected'});
 39             s.end();
 40             });
 41     s.on('close',        /* socket closed */
 42             function() {
 43             log({'info':'closed'});
 44             s.destroy();
 45             reconnect();
 46             });
 47     s.on('timeout',        /* timeout occured */
 48             function() {
 49             log({'info':'timeout'});
 50             s.end(); /* send fin packet */
 51             });
 52     s.on('error',        /* any error occured */
 53             function(err) {
 54             log({'info': err});
 55             });
 56 
 57 }
  • 10 イベントハンドラ登録関数のコール
  • 31-34 データ受信
  • 36-40 finパケットを受信
  • 41-46 ソケットがクローズした
  • 47-51 ソケットがタイムアウトした
  • 52-55 エラーが発生

接続

ソケットの作成とイベントハンドラーの登録が終ったらsocket.connectによりホストに接続する。

 13 socket.connect(PARAM, function () {
 14         log({'info':'connected'});
 15         });
  • 13-15 connectの実行

connectはプログラムの実行中に複数回呼び出しできるが、2回目以降の呼び出しではメモリーリークの原因となるため第二引数のコールバック関数を渡してはいけない。

node.jsがメモリーリークを検出すると以下の警告が出る。

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
    at Socket.EventEmitter.addListener (events.js:175:15)
    at Socket.connect (net.js:668:10)
    at Object._onTimeout (/home/msyaono/project/mike/util/plc/plcconnect.js:88:20)
    at Timer.list.ontimeout (timers.js:101:19)

再接続

コネクションが切断されたり、ソケットのエラーが発生してcloseした場合に再度接続する。

 20 function reconnect() {
 21     setTimeout(function() {
 22             try {
 23             socket.connect(PARAM);
 24             } catch(e) {
 25             log({'info':e});
 26             }
 27             }, 1000);
 28 }
  • 20ー28 再接続の要求が発生して1秒後にconnectを発行する
  • 23 connect()の第二引数は省略すること。(理由は接続を参照)

エラー処理

通信エラーが起こると'error'イベントがスローされるので、これをsocke.on('error')ハンドラで捕捉し各エラーに対する処理を行うことができる。 例えば、以下の例ではコネクションが切断されるとECONNREFUSEDエラーが発生するが、n秒間待って再接続を行なっている。

2012/11/30 10:23:29:694 client:Error: connect ECONNREFUSED
2012/11/30 10:23:29:695 client:closed

接続テスト

(1) 仮想PLCとの通信テスト

Server Client protocol result
plcsrv.js (Beagle) plc (Beagle) melsec手順 12h連続OK
plcsrv.js (Beagle) --- (VPS) --- 無し
plcsrv.js (VPS) plc (Beagle) melsec手順 OK
plcsrv.js (VPS) plcconnect.js (Beagle) melsec手順 OK
  • javascript側はNode.jsのnetモジュールを使用した。

(2) 通信モニタとの連動テスト

windows上のPlcシミュレータとWebアプリMike間で通信を行ない送受信データをリアルタイムでブラウザに表示する。

  • 外部からの接続ではlisten()でホストアドレスを指定しないこと。
Server Client protocol result
mike.js-seq910.js (Beagle) plc (windows2008svR2) melsec手順
  • 確認内容
    1. 送受信レジスタの表示 OK
    2. heartBeatフラグ(D0000)のon/off OK
    3. handshake処理 OK
    4. windows側trace確認 OK

(x)secure通信(TLS/SSL)

Server Client protocol result
secsrv.js (VPS) seccli.js (Beagle) TLS/SSL

付録

shebang

node.jsのスクリプトをシェルから直接実行するにはスクリプトの先頭行にshebangを記述し、実行権限を付与しておく。

 $vi foo.js
 #!/usr/bin/env node
 console.log('hello')

 $ chmod +x foo.js
 $ ./foo.js
   hello

注意事項:外部からの接続

listen(port, [host])の引数hostを指定すると外部から接続できなくなるため、portのみ指定して待ち受けすること。hostが省略されると、どのアドレスに対する接続も受け入れる。

pub/socket-programming-on-nodejs-howto.md.txt · 最終更新: 2013/05/02 07:31 by msyaono