Raspberry Piにインストールされたnode.js上で動作するHTTPサーバとHTTPクライアントのエラー処理とそのログ機能について示します。

実行環境のインストール

Raspberry Piにnode.jsとログライブラリ「log4js」をインストールします。最初にnode.jsを次のコマンドでインストールします。

$ sudo apt-get update
$ sudo apt-get install -y nodejs npm
$ sudo npm cache clean
$ sudo npm install npm n -g
$ sudo n stable

次のコマンドでインストールした 「node」コマンドと「npm」コマンドのバージョンを確認します。

$  node -v
v12.13.1
$  -v
6.12.1

次に log4jsを次のコマンドでインストールします。

$ npm install log4js

node.jsのログ機能について

node.jsのログはlog4jsを使用します。設定ファイルはディレクトリ「config」配下に「log4js.json」を作成します。7行目、8行目を実行することで、それぞれログファイル「system.log」「debug.log」が作成されます。

const log4js = require('log4js');
log4js.configure('config/log4js.json');

const systemLogger = log4js.getLogger('system');
const debugLogger = log4js.getLogger('debug');

systemLogger.info('Start');
debugLogger.debug('Start');

ログはファイルに出力します。最大サイズを「10485760」、3世代管理し、 ディレクト「log」配下に次の二つのログを取得します。ログの形式は「[タイムスタンプ] [取得したログ]」とします。詳細な設定は「log4js」を参照してください。

  • システムログ:ファイル名「system.log」
  • デバッグログ:ファイル名「debug.log」

log4js.json

{
  "appenders": {
    "system": {
      "type": "file",
      "filename": "log/system.log",
      "maxLogSize": 10485760,
      "numBackups": 3,
      "layout": {
        "type": "pattern",
        "pattern": "[%d{yyyy-MM-dd hh:mm:ss}] %m"
      }
    },
    "debug": {
      "type": "file",
      "filename": "log/debug.log",
      "maxLogSize": 10485760,
      "numBackups": 3,
      "layout": {
        "type": "pattern",
        "pattern": "[%d{yyyy-MM-dd hh:mm:ss}] %m"
      }
    }
  },
  "categories": {
    "default": {
      "appenders": ["system"],
      "level": "info"
    },
    "debug": {
      "appenders": ["debug"],
      "level": "debug"
    }
  }
}

HTTPサーバスクリプトの作成

HTTPサーバスクリプト「server.js」を次に示します。

  • 4-8行目までにロギング機能を実装します。
  • 12行目からサーバ機能を実装し、41行目でTCPポート「3000」をlistenします。
  • 14行目でURL「http:/192.168.10.8:3000/servertest」とPostメソッドを設定します。
  • 21行目でサーバのエラー処理を行います。
  • 33行目以降でメソッドやURLが異なる場合の処理を行います。

server.js

var http = require('http');
var querystring = require('querystring');

const log4js = require('log4js');
log4js.configure('config/log4js.json');

const systemLogger = log4js.getLogger('system');
const debugLogger = log4js.getLogger('debug');

debugLogger.debug('Start');

var server = http.createServer(function (req, res) {
  debugLogger.debug("createServer");
  if (req.url === '/servertest' && req.method === 'POST') {
    debugLogger.debug("post");
    var data = '';
    //readableイベントが発火したらデータにリクエストボディのデータを追加
    req.on('readable', function (chunk) {
      data += req.read();
    });
    req.on('error', function (e) {
      debugLogger.debug('problem with Server: ' + e.message);
      res.statusCode = 500;
      res.end('Data Recieve Error!');
    });
    //リクエストボディをすべて読み込んだらendイベントが発火する。
    req.on('end', function () {
      systemLogger.info(data);
      //パースする
      querystring.parse(data);
      res.end(data);
    });
  } else {
    debugLogger.debug('NotFound 404 ');
    res.statusCode = 404;
    res.end('NotFound');
  }
});

// localhostの3000番ポートでサーバーを起動する
server.listen(3000);
console.log('Server is working on port 3000');

HTTPサーバスクリプトの動作確認

次のコマンドでHTTPサーバスクリプトを起動します。

$ node server.js
Server is working on port 3000

作成したサーバスクリプトの動作を確認するために、ブラウザからPOSTメソッドを送信できるChrome拡張「Advanced REST client」を使用します。インストールは、「Advanced REST client」に移動し、「CHROMEに追加」をクリックすると、アプリの一覧に「Advanced REST client」が追加されます。「Advanced REST client」をクリックして、次のように設定してHTTPリクエストのPOSTデータでテキストデータを送信します。

取得したログ「system.log」を次に示します。

[2020-01-01 08:19:48] tomosoft test
null

取得したログ「debug.log」を次に示します。

[2020-01-01 08:19:11] Start
[2020-01-01 08:19:48] createServer
[2020-01-01 08:19:48] post

HTTPクライアントスクリプトの作成

HTTPクライアントスクリプト「client.js」を次に示します。

  • 3-11行目でサーバにアクセスする設定を行います。
  • 13-17行目までにロギング機能を実装します。
  • 21行目でサーバにアクセスし、応答が「resdb」に返されます。
  • 35行目でデータをpostします。
  • 36行目でクライアントのエラー処理を行います。

client.js

var http = require('http');

const options = {
  host: '192.168.10.8',
  port: 3000,
  method: "POST",
  path: "/servertest",
  headers: {
    "Content-Type": "text/plain"
  }
};

const log4js = require('log4js');
log4js.configure('config/log4js.json');

const systemLogger = log4js.getLogger('system');
const debugLogger = log4js.getLogger('debug');

debugLogger.debug('Start');

var reqdb = http.request(options, function (resdb) {
  //サーバからの応答内容の表示
  debugLogger.debug('STATUS: ' + resdb.statusCode);
  debugLogger.debug('HEADERS: ' + JSON.stringify(resdb.headers));
  resdb.setEncoding('utf8');
  resdb.on('data', function (chunk) {
    debugLogger.debug('Response: ' + chunk);
  });
  resdb.on('end', function (chunk) {
    debugLogger.debug('Response ENDED');
  });
});
// データ送信(POST)
data = 'tomosoft test';
reqdb.write(data);
reqdb.on('error', function (e) {
  debugLogger.debug('problem with Client: ' + e.message);
});
reqdb.end();

HTTPクライアントスクリプトの動作確認

先に作成したHTTPサーバスクリプトを起動し、次のコマンドで作成したHTTPクライアントスクリプトを起動します。

$ node client.js

クライアント側で取得したログ「debug.log」を次に示します。

[2020-01-01 09:07:27] Start
[2020-01-01 09:07:27] STATUS: 200
[2020-01-01 09:07:27] HEADERS: {"date":"Wed, 01 Jan 2020 00:07:27 GMT","connection":"close","content-length":"17"}
[2020-01-01 09:07:27] Response: tomosoft testnull
[2020-01-01 09:07:27] Response ENDED

サーバ側で取得したログ「system.log」を次に示します。

[2020-01-01 09:07:27] tomosoft testnull

サーバ側で取得したログ「debug.log」を次に示します。

[2020-01-01 09:06:58] Start
[2020-01-01 09:07:27] createServer
[2020-01-01 09:07:27] post

Raspberry PiのIPアドレスの調べ方

Windows上のコマンドプロンプトで、次のようにpingとarpコマンドをforコマンドと組み合わせ、”192.168.10.1″ から 1 ずつ増加させて “192.168.10.254” まで順番に実行することで、同一ネットワーク内に存在するIPアドレスとそれに対応するMACアドレスを取得できます。

>for /L %i in (1,1,254) do ping -w 500 -n 1 192.168.10.%i > nul && arp -a 192.168.10.%i
>ping -w 500 -n 1 192.168.10.1   1>nul  && arp -a 192.168.10.1
インターフェイス: 192.168.10.6 --- 0xc
  インターネット アドレス 物理アドレス           種類
  192.168.10.1          10-66-82-96-26-60     動的
>ping -w 500 -n 1 192.168.10.2   1>nul  && arp -a 192.168.10.2
>ping -w 500 -n 1 192.168.10.3   1>nul  && arp -a 192.168.10.3
>ping -w 500 -n 1 192.168.10.4   1>nul  && arp -a 192.168.10.4
インターフェイス: 192.168.10.6 --- 0xc
  インターネット アドレス 物理アドレス           種類
  192.168.10.4          c0-38-96-31-71-89     動的
>ping -w 500 -n 1 192.168.10.5   1>nul  && arp -a 192.168.10.5
>ping -w 500 -n 1 192.168.10.6   1>nul  && arp -a 192.168.10.6
ARP エントリが見つかりませんでした。
>ping -w 500 -n 1 192.168.10.7   1>nul  && arp -a 192.168.10.7
>ping -w 500 -n 1 192.168.10.8   1>nul  && arp -a 192.168.10.8
インターフェイス: 192.168.10.6 --- 0xc
  インターネット アドレス 物理アドレス           種類
  192.168.10.8          b8-27-eb-5c-fb-0f     動的
>ping -w 500 -n 1 192.168.10.9   1>nul  && arp -a 192.168.10.9
>ping -w 500 -n 1 192.168.10.10   1>nul  && arp -a 192.168.10.10
   ・・・・

サーバのエラー「Error: listen EADDRINUSE :::3000」

サーバを起動するときに、次のように「Error: listen EADDRINUSE :::3000」が表示され、起動できないことがあります。

events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE :::3000
    at Object._errnoException (util.js:1022:11)
    at _exceptionWithHostPort (util.js:1044:20)
    at Server.setupListenHandle [as _listen2] (net.js:1367:14)
    at listenInCluster (net.js:1408:12)
    at Server.listen (net.js:1492:7)
    at Object. (/home/pi/datacollection/collection.js:77:8)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)

これは、すでにTCPポート「3000」が使用されているためで、PSコマンドで確認するとプロセス「node」が動作していました。

$ ps -all
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S  1000   613   564  0  80   0 -  2182 poll_s tty1     00:00:00 bash
0 T  1000  1473  1240  0  80   0 - 27907 -      pts/0    00:00:00 node
0 R  1000  1647  1240  0  80   0 -  1667 -      pts/0    00:00:00 ps

次のコマンドでプロセス「node」をkillします。

$ kill -9 1473