2015年8月28日金曜日

node.jsとwebsocket

node.js自体のinstall方法は色々な方が書かれているのでここでは飛ばします。
今回はさくらVPS上でubuntu14.04LTSでサーバーを運用しています。

javascript初心者なので何かとつまらないところで躓いてますが、なんとか通信が動くようになりました。

最初にhttpsで接続し、upgradeでwebsocketに切り替える動作になるので、サーバー認証、クライアント認証はhttps接続時に行います。
最初に躓いたのは、自己認証局の証明書(いわゆるオレオレ証明書です)でMacのSafari(8.0.8)からwebsocketに接続しようとすると接続がハネられてしまうことに気が付かなかったため数日間悩みました。Chromeで接続するとちゃんと接続できたので、Safariの仕様のようです。wiresharkでみてみるとサーバー側からはリクエストが出ていますがSafariからクライアント証明書を送っていないようです。
最終的にはSafariではなくRaspberryPi上の自作プログラムから接続するので、このまま進めます。

最初に必要なモジュールを読み込みます。
var WebSocketServer = require('ws').Server;
var https = require('https');
var fs = require('fs');

後で変更しそうな設定値を記述したconfigファイルを用意して読み込みます。
var config = require('./config');

httpsのセキュリティ条件をoptsで設定します。
  var opts = {
    key: fs.readFileSync(config.keyFile),
    cert: fs.readFileSync(config.certFile),
    ca: fs.readFileSync(config.caFile),
    ciphers: "ALL:!EXP:!ADH:!LOW:!SSLv2:!SSLv3:!DES:!3DES:!RC4",
    honorCipherOrder: true,
    secureProtocol: "TLSv1_2_method",
    requestCert: true,
    rejectUnauthorized: true
  };

クライアント認証をするには最後のrejectUnauthorized:trueが必要です。
これがないとやりとりはするけど認証されてない相手でも通信を許してしまいます。
あとdebug時にwiresharkで暗号通信の中身を確認したい場合はciphers:の先頭のALL:をkRSA:にする必要があります。これをしないと暗号が解けないので中身が見えません。

  // connect from house controller
  var houseControllerServer = https.createServer(opts);
  var wss = new WebSocketServer({server:houseControllerServer});
  var houseControllerConnections = [];

  houseControllerServer.listen(config.houseControllerPort, function() {
    console.log("house controller listing on port %d", config.houseControllerPort);
  });
指定されたportでアクセスが来るのを待ちます。

  wss.on('connection', function (ws) {
    // connectionイベントの処理
    console.log('connect from house controller');
    houseControllerConnections.push(ws); // 接続先を記録しておきます。
  // ここにwebsocket接続時の処理を追加します。

    ws.on('close', function () {
      // closeイベントの処理
      console.log('disconnect from hosue controller');
      // closeする接続先を記録から除いています。
      houseControllerConnections = houseControllerConnections.filter(function (conn, i) {
        return (conn === ws) ? false : true;
      });
     // ここにdisconnect時の処理を追加します。
    });

    ws.on('message', function (message) {
      // mesageイベントの受信処理
      var OU = ws._socket.getPeerCertificate().subject.OU;
      var msg = JSON.parse(message);
      // ここに通信相手からのメッセージの処理を追加します。
      console.log(msg);
    });
  });

  //送信はイベント処理ではないのでfunctionです。
  function sendWebsocket(message) {
    houseControllerConnections.forEach(function (con, i) {
      // 登録されている通信相手にメッセージを送信します。
      con.send(JSON.stringify(message));
    });
  }

以上で接続、終了、受信、送信の処理となります。


0 件のコメント:

コメントを投稿