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