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
