7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Node.jsAdvent Calendar 2021

Day 10

【Node.js 2021(2つ目)】 Node.js での UDP・TCP通信をシンプルに試す(2021年12月)

Last updated at Posted at 2021-12-09

この記事は、2021年の Node.js のアドベントカレンダー の 10日目の記事です。

内容は、以下の記事を書く中で使った「zigsim-ws」の中で利用されている「dgram」が気になって調べたり試したりしたことを、記事として書いた形です。

●【IoTLT 2021】 ZIG SIM から送られるデータを p5.js Web Editor上で活用してみる - Qiita
 https://qiita.com/youtoy/items/caca41a68ab3bff6ffa6

zigsim-ws のプログラムと UDP通信

zigsim-ws は、プロトタイピングに役立つスマホアプリの「ZIG SIM」を、ブラウザ(HTML+JavaScript のプログラム)との間で通信させる時に利用するものです。
軽く補足をすると、ZIG SIM がデータを送る時に用いる通信が UDP・TCP で、ブラウザ上の JavaScript のプログラムでは直接は扱えないものになるので、それらの間で通信できるようにするためには仲介役が必要です。zigsim-ws は、その仲介役として UDP 通信をブラウザ上で動く JavaScript が扱える WebSocket の通信に変換する役割を担います。

●zigsim-ws/index.js at master · acrylicode/zigsim-ws
 https://github.com/acrylicode/zigsim-ws/blob/master/index.js

そのプログラムは、以下のような実装になっています。

const dgram = require('dgram');
const WebSocket = require('ws');

function init(updPort = 50000, wsServerPort = 8080) {
    const updServer = dgram.createSocket('udp4');
    const wss = new WebSocket.Server({ port: wsServerPort });
    console.log(`websocket server listening on port: ${wsServerPort}`)

    wss.on('connection', (ws) => {
        console.log(`New client connected to the websocket. Number of clients: ${wss.clients.size}`)
    });

    updServer.on('error', (err) => {
        console.log(`upd server error:\n${err.stack}`);
        updServer.close();
    });

    updServer.on('message', (msg) => {
        wss.clients.forEach(client => {
            if (client.readyState === WebSocket.OPEN) {
                client.send(msg.toString())
            }
        });
    });

    updServer.on('listening', () => {
        const address = updServer.address();
        console.log(`udp server listening on port: ${address.port}`);
    });
    updServer.bind(updPort);
}

module.exports.init = init;

冒頭の 2行目の部分は、WebSocketサーバーを動かすためのものを読み込んでいますが、1行目で「dgram」を読み込んでいます。

dgram について見てみる

npm のページを見て、さらに情報をチェックしようと思って以下にアクセスしました。
 ●dgram - npm
  https://www.npmjs.com/package/dgram
そうすると、以下をのような記載が...(deprecated になってる...)
dgram.jpg

そして、さらに調査をしていきました。

dgram についてさらにチェック

先ほどの npm のページの記載をあらためて見てみると 「As it's a core Node module, we will not transfer it ...」 と書かれていました。

さらに、Node.js の公式情報を合わせて見てみると、Node.js自体の機能の話で「UDP/datagram sockets」というものが出てきました。

●UDP/datagram sockets | Node.js v17.2.0 Documentation
 https://nodejs.org/api/dgram.html

結論を書くと、先ほどの zigsim-ws は、こちらの Node.js内のものを呼んでいたようです。
(※ 自分が zigsim-ws のプログラムを実行していたフォルダ等を見ると、node_modulesフォルダ以下に dgram のフォルダがなかった)

そして、Node.js での UDP通信の話を見ていくと、以下の内容も見つかりました。
こちらの記事でも、Node.js に元から入っていそうな dgram の話をされています。

●Node.jsでUDP通信する - Re: note
 https://hikoleaf.hatenablog.jp/entry/2019/06/08/235753

Node.js で UDP通信を実行する

それでは、実際に Node.js での UDP通信を、自分の環境で実行してみます。

2者間の単純な通信

先ほど、調べて出てきたと書いていたサイトを見てみると、2者間でのシンプルな通信の例が掲載されていました。

そこで、まずはこの例をそのまま利用します。
1点、元の記事で $ npm install dgram を実行する手順が書いてありますが、これは不要だと思われます。
(これをやってしまうと、上記で deprecated となってたやつを読み込んでしまいそうな予感...)

以下の2つのプログラムを用意し、2つのターミナルを開いて、それぞれで 1つずつのプログラムを実行すると、定期的にデータのやりとりが行われている様子が確認できました。

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');

socket.on('listening', () => {
    const address = socket.address();
    console.log('UDP socket listening on ' + address.address + ":" + address.port);
});

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

    socket.send(message, 0, message.length, PORT_B, HOST_B, (err, bytes) => {
        if (err) throw err;
    });
});

socket.bind(PORT_A, HOST_A);
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);

これらを実行すると、一方から一定間隔で他方へカウントアップする文字列を送り、それを受信した側はエコーバックするという動作が確認できました。

そういえば、●● over UDP という形のものを使うことはよくあったけど、UDP を直接扱うようなことはこれまでなかったかも。

Node.js で TCP通信を実行する

この後は、UDP通信を行うプログラムに手を入れて何かやろうかとも思ったのですが、ふと「TCP はどんな感じなんだろう?」という考えが頭をよぎりました。

そして、記事を検索したところ、以下のものが出てきました。
非常にシンプルなプログラムが掲載されていて、試してみるのにちょうど良さそうです。

●Node.jsでTCP通信する - Re: note
 https://hikoleaf.hatenablog.jp/entry/2019/06/09/131620

UDP に関する記事と同様に $ npm install net を実行する手順が書いてありますが、これは不要な感じが。

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');
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');
});

そのまま動かしてみたら、以下のように通信が行えました。
1度データを送信すると、送信側は終了する挙動のようだったので、何度か送信をやってみています。

そういえば、●● over TCP という形のものを...(以降、省略)

おわりに

既存のサンプルを動かしただけではありますが、プログラムをざっくり見てみると、Node.js ではかなりシンプルな実装で UDP や TCP の通信を扱えるんだな、というのを感じました。

たしか、「M5Stack系の UIFlow で、UDP を扱うブロックがあったな」とか思い浮かんだので、それとつないでみるとか、何かこれを使ったデバイス/アプリ/サービス間通信を試せたら、とか思っています。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?