CLOVER🍀

That was when it all began.

Node.jsで、Echo Client/Serverを書いてみる

ちょっとした、Node.jsのお勉強にということで。Echo ServerとClientを書いてみることにしました。標準APIで。

環境。

$ node -v
v8.4.0

ふつうにTCPソケットを扱いたいので、netモジュールを使えばいい感じでしょうかね。

Net | Node.js v8.11.4 Documentation

APIドキュメント中にサンプルコードもあることですし、こちらを参考にしてみましょう。

net.createServer

net.createConnection

では、書いていってみます。

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のこと

これって、こういうのがふつうなのかな…?