はじめに
Node.jsで使うことのできる通信方式としては、TCPソケット、ストリーミングIPCエンドポイント、そしてHTTPインターフェースです。HTTPインターフェースに関しては、実際にはTCPソケットとして動いているので、実質前の2つになります。
では、TCPソケットとストリーミングIPCエンドポイントの違いは何でしょうか?
TCPソケットは、TCP/IPの上でソケットを用いて行う通信方式です。
一方のストリーミングIPCエンドポイントは、IPC(Inter-Process Communication)の下、同一マシーン内でプロセス間通信をストリーミングで行う通信方式です。
このストリーミングIPCエンドポイントをUNIX上で実現されている技術が、『 Unix domain sockets 』です。
UNIXドメインソケットとは?
ローカルで開かれたソケットファイルを通じて、サーバー側とクライアント側とで通信を行う方法です。
Node.jsでは適用されていませんが、一般的には unix://
でURLが始まります。
TCPで行う通信と異なり、ローカルファイルを指定して通信を行うため、ドメインの解決や外部通信をしません。
そのため、TCPに比べ速いです。
その検証に関しては、 Performance Analysis of Various Mechanisms for Inter-process Communication をご覧ください。
使ってみよう!
この記事のサンプルプログラムは unix-domain-socket にあります。
UNIXドメインソケットは、Node.jsのビルドインモジュールの net
の中で提供されています。
そのため、この記事では net
を主に用いてプログラムを書いていきます。
Net | Node.js
送信側
以下のようなプログラムを作成しました。
import net from 'net';
// UNIXドメインソケットのコネクションを作成する
// net.createConnectionの引数にファイルを指定するとUNIXドメインソケットで繋がる
const client = net.createConnection('/tmp/unix.sock');
client.on('connect', () => {
console.log('connected.');
});
client.on('data', (data) => {
console.log(data.toString());
});
client.on('end', () => {
console.log('disconnected.');
});
client.on('error', (err) => {
console.error(err.message);
});
client.write('hello');
受信側
以下のようなプログラムを作成しました。
import net from 'net';
import fs from 'fs';
// サーバーを設定
const server = net.createServer((connection) => {
console.log('connected.');
connection.on('close', () => {
console.log('disconnected.');
});
connection.on('data', (data) => {
console.log(data.toString());
});
connection.on('error', (err) => {
console.error(err.message);
});
connection.write('unix domain socket');
connection.end();
});
// ソケットファイルを削除(存在するとlistenできない)
try {
fs.unlinkSync('/tmp/unix.sock');
} catch (error) {}
// UNIXドメインソケットでlistenする
server.listen('/tmp/unix.sock');
実行してみる
ともに同じ仮想サーバー内で実行しています。
左側は送信側で、右側は受信側です。
おわりに
このUNIXドメインソケットは、ローカルマシーン内でプロセス間で通信を行う場合に効果を発揮します。
例えば、KubernetesのPod内のコンテナ間で通信を行う場合に使うことができます。
ボリュームを共有してマウントすることで通信ができるので、ドメインの名前解決に縛られることが無くなります。
ポートで通信を行う場合と比べて制限を受けない部分もあるので、一度使ってみてはどうですか?