【Node-RED 2021】 Node.js との間でシンプルな UDP・TCP通信をやってみる


この記事は、2021年の Node-RED のアドベントカレンダー の 21日目の記事です。

今回の内容

今回は、以下の記事でも書いていたシンプルな UDP・TCP での通信に関するものです。
以下で用いた Node.js のプログラムと、Node-RED上で作成したフローとの間で、シンプルな UDP・TCP通信をやってみる話になります。

●【Node.js 2021(2つ目)】 Node.js での UDP・TCP通信をシンプルに試す(2021年12月) - Qiita
 https://qiita.com/youtoy/items/385feead64ff905e9f76

TCP による通信を試す

Node-RED から TCP でデータを送る

まずは、Node-RED から Node.js のプログラムに対してデータを送る方向で、TCP の通信を試してみます。

Node.js側は、以前の記事でも用いた以下のプログラムになります。
3000番ポートで待ち受けをする、という内容になります。

const net = require('net');

const server = net.createServer(socket => {
    socket.on('data', data => {
        console.log(data + ' from ' + socket.remoteAddress + ':' + socket.remotePort);
        socket.write('server -> Repeating: ' + data);
    });

    socket.on('close', () => {
        console.log('client closed connection');
    });
}).listen(3000);

console.log('listening on port 3000');

上記に対して、TCP通信を使った文字列の送信をやってみます。
用いる TCP のノードは、以下の中の「tcp out」になります。

フローは、以下のようにシンプルな内容にしました。

2つのノードの設定は、それぞれ以下のとおりです。

あとは、デプロイ後に injectノードの処理を行うと、Node.js側で以下の出力が得られます(以下は、2回処理を行った後の結果です)。

Node-RED側が TCP でデータを受けとる

今度は逆向きの流れです。

Node.js のプログラムは、過去に使った以下のものをそのまま使います。
以下は、Node-RED側の準備ができた後に実行します。

const net = require('net');

const client = net.connect('3000', 'localhost', () => {
    console.log('connected to server');
    client.write('Hello World!');
});

client.on('data', data => {
    console.log('client-> ' + data);
    client.destroy();
});

client.on('close', () => {
    console.log('client-> connection is closed');
});

Node-RED側は、TCP通信に関する 3つのノードのうち「tcp in」を使います。
フローは以下のように、debugノードと接続するだけです。

tcp inノードの設定は、以下のとおりです。

フローをデプロイした後、Node.js側のプログラムを実行します。
そうすると、以下のように Node-RED側で文字列を受信できているのがデバッグ出力で確認できました。

UDP による通信を試す

Node-RED から UDP でデータを送る

次は、UDP を用いた通信です。

Node.js側は、過去に書いた記事で用いていたものを流用します。
具体的な受信処理の内容は、以下のように 3003番ポートで待ち受けをするというものです。

const dgram = require('dgram');

const PORT_A = 3002;
const HOST_A ='127.0.0.1';

const PORT_B = 3003;
const HOST_B ='127.0.0.1';

const socket = dgram.createSocket('udp4');

var count = 0;

setInterval(() => {
    count++;
    const data = Buffer.from(String(count));
    socket.send(data, 0, data.length, PORT_A, HOST_A, (err, bytes) => {
        if (err) throw err;
    });
}, 500);


socket.on('message', (message, remote) => {
    console.log(remote.address + ':' + remote.port +' - ' + message);
});

socket.bind(PORT_B, HOST_B);

Node-RED側は以下の 2つのノードのうち、「udp out」を用います。

フローは以下のようなものにしました。

上記の injectノードは、TCP を用いた時と同じ設定になります。
また、udp outノードの設定は以下のとおりです。

3003番ポートに、injectノードから受けとった文字列を送るというものです。
Node.js側のプログラムを動かし、その後に injectノードの処理を実行すると、Node.js側で以下の出力を得られました。

Node-RED側で UDP によるデータ受信

今度は、逆方向を試します。
上記で用いたプログラムは、3002番ポートに定期的に文字列を送信します。

そこで、以下のように udp inノードを用いたフローを作ってみました。

そして、udp inノードの設定は以下のようにしています。

あとは、Node-RED側のデバッグ出力に定期的に文字列が表示されると思ったのですが、なぜかそれが表示されず...

その後の調査後

その後、あれこれ調査や検証をしたのですが、どうやらセキュリティソフトのファイアウォールが影響していたようでした。

その対処をした後に再度試したら、以下のように UDP での文字列の受信ができました。

Node-RED内で UDP通信

上記が想定通りの動作をしていなかった時に、Node-RED内で送受信の両方を試したらどうなるかやってみた時の記録です。
上記の問題が解決したので不要な部分になりましたが、メモ的に残しておこうかと。

基本的な設定は、上記の送信・受信のそれぞれを行ったものと同じです。
唯一異なるのは、送受信のポートを同一にしている部分くらいです。

この状態で injectノードの処理を実行してみたところ、以下のようなデバッグ出力が得られました。

上で書いていたセキュリティソフトの話について、異なるアプリ間での通信に影響が出ていたようでした。
(なぜ片方向は通っていたのかとかは、調査しきれてないですが...)

おわりに

シンプルな UDP・TCP通信を Node-RED で試してみて、(セキュリティソフトの件があったのを除けば)あっさりと通信を行うことができました。

シンプルに通信をさせた場合に有効に活用できそうか、ということ等を考えてみたいと思います。