名前付きパイプ(Named Pipe / FIFO) は、ファイルシステム上に名前を持つ特殊なファイルで、プロセス間でデータをやり取りするための仕組みです。
# 通常のパイプ(無名パイプ)
ls | grep .txt
# ↑ lsの出力をgrepの入力に直接つなぐ(親子プロセス間のみ)
# 名前付きパイプ
mkfifo /tmp/mypipe # ファイルシステム上に作成
ls > /tmp/mypipe & # プロセス1が書き込み
cat < /tmp/mypipe # プロセス2が読み込み(無関係なプロセス間でOK)
// 名前付きパイプの動作イメージ
// プロセスA(書き込み側)
FileOutputStream fos = new FileOutputStream("/tmp/mypipe");
fos.write("Hello".getBytes()); // ここでブロック(読み手が現れるまで)
// プロセスB(読み込み側)
FileInputStream fis = new FileInputStream("/tmp/mypipe");
int data = fis.read(); // プロセスAが書き込むまでブロック
重要な性質:
# 簡単に作成できる
mkfifo /tmp/mypipe
# 通常のファイルのように扱える
echo "test" > /tmp/mypipe &
cat /tmp/mypipe
Windowsにも名前付きパイプはありますが...
// Windowsの名前付きパイプは特殊なAPI経由でしかアクセスできない
// 通常のFileInputStream/OutputStreamでは使えない!
// こんな形式になる
String pipeName = "\\\\.\\pipe\\mypipe";
// しかもWin32 APIを直接使う必要がある(JNAなど必要)
Windowsの名前付きパイプの問題点:
\\.\pipe\名前 という形式FileInputStreamでは開けない// JNAライブラリを使った例(複雑!)
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.ptr.IntByReference;
public class WindowsNamedPipe {
public static void main(String[] args) {
// パイプ作成
WinNT.HANDLE hPipe = Kernel32.INSTANCE.CreateNamedPipe(
"\\\\.\\pipe\\mypipe",
WinBase.PIPE_ACCESS_DUPLEX,
WinBase.PIPE_TYPE_BYTE,
1, 1024, 1024, 0, null
);
// 接続待ち
Kernel32.INSTANCE.ConnectNamedPipe(hPipe, null);
// データ送受信...
// (さらに複雑なコードが続く)
}
}
ソケットは クロスプラットフォーム で、Java標準APIで簡単に使えます。
// どのOSでも同じコードで動く!
// サーバー側(送信側)
ServerSocket server = new ServerSocket(12345);
Socket client = server.accept();
OutputStream os = client.getOutputStream();
os.write("Hello".getBytes());
// クライアント側(受信側)
Socket socket = new Socket("localhost", 12345);
InputStream is = socket.getInputStream();
int data = is.read();
| 特徴 | 名前付きパイプ | ソケット |
|---|---|---|
| Linux/Mac対応 | ◎ 簡単 | ◎ 簡単 |
| Windows対応 | △ 複雑 | ◎ 簡単 |
| Java標準API | Linux/Macのみ | 全OS |
| ネットワーク越し | × 不可 | ◎ 可能 |
| 同一マシン限定 | ◎ 高速 | △ やや遅い |
| セットアップ | mkfifo必要 |
不要 |
# Linux/Macで同一マシン内の簡単な通信
mkfifo /tmp/log_pipe
# ログ収集など
./app1 > /tmp/log_pipe &
./app2 < /tmp/log_pipe
// クロスプラットフォーム
// ネットワーク越しの通信も可能
// より柔軟な実装
ServerSocket server = new ServerSocket(8080);
// どこからでも接続可能
実際のプロジェクトでは、ソケット版の方が無難です!