Edited at

Node.jsでもUNIXドメインソケットを使いたい


はじめに

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内のコンテナ間で通信を行う場合に使うことができます。

ボリュームを共有してマウントすることで通信ができるので、ドメインの名前解決に縛られることが無くなります。

ポートで通信を行う場合と比べて制限を受けない部分もあるので、一度使ってみてはどうですか?