ちょっとした、Node.jsのお勉強にということで。Echo ServerとClientを書いてみることにしました。標準APIで。
環境。
$ node -v
v8.4.0
ふつうにTCPソケットを扱いたいので、netモジュールを使えばいい感じでしょうかね。
Net | Node.js v8.11.4 Documentation
APIドキュメント中にサンプルコードもあることですし、こちらを参考にしてみましょう。
では、書いていってみます。
Server側
書いてみたコードは、こんな感じ。第1引数でListen Portを受け取るようにしました。
server.js
const net = require("net"); const args = process.argv.slice(2); const port = args.length > 0 ? parseInt(args[0]) : 8080; const logger = fun => console.log(`[${new Date()}] ${fun.call(null)}`); const server = net.createServer(socket => { logger(() => `accept client = ${socket.remotePort}`); socket.setEncoding("utf8"); // as String socket.on("data", (data) => { const trimmedData = data.trim(); logger(() => `receive data[${trimmedData}]`); socket.write(`★${trimmedData}★`); }); socket.on("close", () => logger(() => `disconnect client = ${socket.remoteAddress}:${socket.remotePort}`)); }); server.on("error", err => { throw err; }); server.on("close", () => logger(() => "Echo Server, Shutdown")); server.listen({ host: "localhost", port: port }, () => { logger(() => `Echo Server[${port}], Startup`); });
net.createServerでアクセスしてきたSocketへの処理が書けるようなので、データが送られてきたら(dataイベント)
「★」を付けて送り返すようにしてみました。
const server = net.createServer(socket => { logger(() => `accept client = ${socket.remotePort}`); socket.setEncoding("utf8"); // as String socket.on("data", (data) => { const trimmedData = data.trim(); logger(() => `receive data[${trimmedData}]`); socket.write(`★${trimmedData}★`); }); socket.on("close", () => logger(() => `disconnect client = ${socket.remoteAddress}:${socket.remotePort}`)); });
Socket#setEncodingで「utf8」を指定していますが、これを指定するとdataイベントを受け取った時にデータを
Stringとして扱えるようです。
socket.setEncoding("utf8"); // as String
指定しなかった場合、Bufferが渡ってきました。その場合は、デコードが必要なのでしょう。
あとは例外の受け取りとClose時のログ出力を書いて、
server.on("error", err => { throw err; }); server.on("close", () => logger(() => "Echo Server, Shutdown"));
Server#listenで待ち受け開始ですと。
server.listen({ host: "localhost", port: port }, () => { logger(() => `Echo Server[${port}], Startup`); });
Server側はこんな感じで。
Client側
続いて、Client側はこういう感じにしてみました。
client.js
const net = require("net"); const args = process.argv.slice(2); let host; let port; let message; if (args.length > 2) { host = args[0]; port = parseInt(args[1]); message = args[2]; } else if (args.length > 1) { host = "localhost"; port = parseInt(args[0]); message = args[1]; } const logger = fun => console.log(`[${new Date()}] ${fun.call(null)}`); const client = net.createConnection({ host: host, port: port }, () => { logger(() => "start client"); }); client.on("connect", () => { logger(() => `connected server[${host}:${client.remotePort}]`); client.write(message); logger(() => `send message[${message}]`); }); client.on("data", data => { logger(() => `receive message[${data}]`); client.destroy(); }); client.on("close", () => logger(() => "disconnect server"));
起動引数は、接続先ホスト/ポート/メッセージか、ポート/メッセージのどちらかにしました。
if (args.length > 2) { host = args[0]; port = parseInt(args[1]); message = args[2]; } else if (args.length > 1) { host = "localhost"; port = parseInt(args[0]); message = args[1]; }
接続は、net.createConnectionで行えばよいようです。
const client = net.createConnection({ host: host, port: port }, () => { logger(() => "start client"); });
接続できたら、メッセージを送信。
client.on("connect", () => { logger(() => `connected server[${host}:${client.remotePort}]`); client.write(message); logger(() => `send message[${message}]`); });
データが戻ってきたら、ログ出力して切断。
client.on("data", data => { logger(() => `receive message[${data}]`); client.destroy(); });
終了。
client.on("close", () => logger(() => "disconnect server"));
動作確認
それでは、動作確認をしてみましょう。
まずはServer側を起動。
$ node server.js [Tue Sep 12 2017 23:36:51 GMT+0900 (JST)] Echo Server[8080], Startup
Clientからメッセージ送信。
$ node client.js 8080 'Hello World' [Tue Sep 12 2017 23:37:25 GMT+0900 (JST)] start client [Tue Sep 12 2017 23:37:25 GMT+0900 (JST)] connected server[localhost:8080] [Tue Sep 12 2017 23:37:25 GMT+0900 (JST)] send message[Hello World] [Tue Sep 12 2017 23:37:25 GMT+0900 (JST)] receive message[★Hello World★] [Tue Sep 12 2017 23:37:25 GMT+0900 (JST)] disconnect server
この時の、Server側のログ。
[Tue Sep 12 2017 23:37:25 GMT+0900 (JST)] accept client = 58564 [Tue Sep 12 2017 23:37:25 GMT+0900 (JST)] receive data[Hello World] [Tue Sep 12 2017 23:37:25 GMT+0900 (JST)] disconnect client = 127.0.0.1:58564
OKそうです。
まとめ
Node.jsのちょっとした勉強ということで、Echo Client/Serverを書いてみました。
このネタ、言語を覚える時のパターンのひとつとしてやることが多いのですが、今回はバッファリングとかでハマったりしなかったですね。
ただ、このコールバックのAPIに慣れないという感じはします…。
ところで
APIドキュメントのサンプルを眺めていて、こういう例にちょっと気持ち悪かったのですが。
net.createConnection
const client = net.createConnection({ port: 8124 }, () => { //'connect' listener console.log('connected to server!'); client.write('world!\r\n'); });
コールバック関数側で、その呼び出し元に返した変数を触ってるってやつです。
※ここでは、clientのこと
これって、こういうのがふつうなのかな…?