【PHP8.x】posix_mkfifo()関数の使い方
posix_mkfifo関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
posix_mkfifo関数は、UNIX系オペレーティングシステムにおいて、プロセス間でデータをやり取りするための「名前付きパイプ」(FIFO: First-In, First-Out)を作成する関数です。名前付きパイプは、通常のファイルとは異なり、ディスク上にデータを永続的に保存するのではなく、複数のプロセスが互いに通信するための特殊なファイルインターフェースとして機能します。この関数は、最初の引数として作成する名前付きパイプのパスを文字列で指定し、第二引数としてそのパイプのアクセス権限(パーミッション)を整数値で指定します。パーミッションは、他のファイルと同様に、例えば0644のように8進数で指定することが一般的です。posix_mkfifo関数は、名前付きパイプの作成に成功した場合にtrueを返し、失敗した場合にはfalseを返します。失敗の例としては、指定されたパスにすでにファイルが存在する場合や、十分な権限がない場合が挙げられます。これにより、PHPアプリケーションから、関連性のない異なるプロセス間でデータの送受信を行うための経路を確立できます。関数がfalseを返した際には、エラー処理を行うことが重要です。
構文(syntax)
1<?php 2$fifoPath = '/tmp/my_php_fifo'; 3$permissions = 0644; 4 5if (posix_mkfifo($fifoPath, $permissions)) { 6 echo "FIFOスペシャルファイル '{$fifoPath}' が作成されました。\n"; 7} else { 8 echo "FIFOスペシャルファイル '{$fifoPath}' の作成に失敗しました。\n"; 9} 10?>
引数(parameters)
string $filename, int $permissions
- string $filename: 作成するFIFO(名前付きパイプ)のパスを指定する文字列
- int $permissions: FIFOのパーミッションを指定する整数(0から0777の範囲)
戻り値(return)
bool
名前付きパイプ(FIFO)を作成し、成功した場合は true を、失敗した場合は false を返します。
サンプルコード
PHP posix_mkfifoとposix_killでFIFO通信する
1<?php 2 3/** 4 * Executes a PHP POSIX FIFO communication example with process signaling. 5 * 6 * This function demonstrates the creation of a named pipe (FIFO) using posix_mkfifo 7 * for inter-process communication (IPC). It launches a child process (itself) 8 * that writes to the FIFO, while the main process reads from it. 9 * It also shows how to use posix_kill to send a signal (SIGTERM) 10 * to the child process after a certain amount of data has been received, 11 * simulating process control. 12 * 13 * Requires a POSIX-compliant operating system (e.g., Linux, macOS) 14 * and PHP CLI with the 'posix' extension enabled. 15 */ 16function runFifoCommunicationExample(): void 17{ 18 // Access command line arguments to distinguish between main and child processes. 19 global $argv; 20 21 if (!isset($argv[1])) { 22 // --- Main Process Logic (Parent) --- 23 // Generate a unique path for the FIFO to prevent conflicts. 24 $fifoPath = '/tmp/php_fifo_' . uniqid(); 25 26 // Create a FIFO (named pipe) with read/write permissions for all. 27 if (!posix_mkfifo($fifoPath, 0666)) { 28 echo "Main process: Error: Could not create FIFO at {$fifoPath}. " . posix_strerror(posix_get_last_error()) . "\n"; 29 exit(1); 30 } 31 echo "Main process: FIFO created at: {$fifoPath}\n"; 32 33 // Construct the command to launch this same script as a child process (writer). 34 // PHP_BINARY is a constant holding the path to the PHP executable. 35 $cmd = PHP_BINARY . ' ' . __FILE__ . ' writer ' . $fifoPath; 36 $descriptorspec = [ 37 0 => ['pipe', 'r'], // Child's stdin 38 1 => ['pipe', 'w'], // Child's stdout 39 2 => ['pipe', 'w'] // Child's stderr 40 ]; 41 // Start the child process. 42 $process = proc_open($cmd, $descriptorspec, $pipes, null, null); 43 44 if (!is_resource($process)) { 45 echo "Main process: Error: Could not start writer process.\n"; 46 unlink($fifoPath); // Clean up FIFO before exiting. 47 exit(1); 48 } 49 50 // Get the process ID (PID) of the child writer process. 51 $status = proc_get_status($process); 52 $writerPid = $status['pid']; 53 echo "Main process: Writer process started with PID: {$writerPid}\n"; 54 55 // Open the FIFO for reading in the main process. 56 // This call will block until the writer process opens its end for writing, 57 // establishing the connection. 58 $readHandle = fopen($fifoPath, 'r'); 59 if (!$readHandle) { 60 echo "Main process: Error: Could not open FIFO for reading.\n"; 61 if ($writerPid) { 62 posix_kill($writerPid, SIGTERM); // Attempt to kill child if reader fails. 63 } 64 proc_close($process); 65 unlink($fifoPath); 66 exit(1); 67 } 68 69 echo "Main process: Reading from FIFO...\n"; 70 $dataCount = 0; 71 // Read data line by line from the FIFO until end-of-file. 72 while (!feof($readHandle)) { 73 $data = fgets($readHandle); 74 if ($data !== false) { 75 echo "Main process: Received: " . trim($data) . "\n"; 76 $dataCount++; 77 } 78 79 // After receiving a few messages, send a termination signal (SIGTERM) 80 // to the writer process using posix_kill. 81 if ($dataCount >= 3) { 82 echo "Main process: Sending SIGTERM to writer process (PID: {$writerPid})...\n"; 83 if (posix_kill($writerPid, SIGTERM)) { 84 echo "Main process: SIGTERM sent successfully.\n"; 85 } else { 86 echo "Main process: Failed to send SIGTERM. " . posix_strerror(posix_get_last_error()) . "\n"; 87 } 88 break; // Exit loop as we've signaled the writer to stop. 89 } 90 usleep(100000); // Small delay to prevent busy-waiting. 91 } 92 93 fclose($readHandle); // Close the reading end of the FIFO. 94 echo "Main process: Finished reading from FIFO.\n"; 95 96 // Wait for the writer process to terminate and clean up its resources. 97 $returnCode = proc_close($process); 98 echo "Main process: Writer process exited with code: {$returnCode}\n"; 99 100 // Clean up the created FIFO file from the filesystem. 101 if (file_exists($fifoPath) && unlink($fifoPath)) { 102 echo "Main process: FIFO deleted.\n"; 103 } else { 104 echo "Main process: Failed to delete FIFO or it no longer exists.\n"; 105 } 106 107 } else if ($argv[1] === 'writer') { 108 // --- Child Process Logic (Writer) --- 109 // The FIFO path is passed as the second command-line argument. 110 $fifoPath = $argv[2]; 111 $writerPid = getmypid(); // Get the current process's PID. 112 echo "Writer process (PID: {$writerPid}): Opening FIFO for writing: {$fifoPath}\n"; 113 114 // Open the FIFO for writing. 115 // This call will block until a reader process opens its end. 116 $writeHandle = fopen($fifoPath, 'w'); 117 if (!$writeHandle) { 118 echo "Writer process (PID: {$writerPid}): Error: Could not open FIFO for writing.\n"; 119 exit(1); 120 } 121 122 echo "Writer process (PID: {$writerPid}): Writing to FIFO...\n"; 123 for ($i = 1; $i <= 10; $i++) { 124 // Check if the write handle is still valid before writing. 125 if (!is_resource($writeHandle) || feof($writeHandle)) { 126 echo "Writer process (PID: {$writerPid}): FIFO connection closed unexpectedly.\n"; 127 break; 128 } 129 if (!fwrite($writeHandle, "Data line {$i}\n")) { 130 echo "Writer process (PID: {$writerPid}): Error writing to FIFO. Exiting.\n"; 131 break; 132 } 133 echo "Writer process (PID: {$writerPid}): Wrote 'Data line {$i}'.\n"; 134 sleep(1); // Simulate some work. 135 } 136 137 fclose($writeHandle); // Close the writing end of the FIFO. 138 echo "Writer process (PID: {$writerPid}): Finished writing to FIFO. Exiting.\n"; 139 exit(0); 140 } 141} 142 143// Execute the main function when the script is run. 144runFifoCommunicationExample();
posix_mkfifoは、PHPでUNIXライクなシステムにおける名前付きパイプ(FIFO:First-In, First-Out)を作成するための関数です。これは、複数の独立したプロセス間でデータをやり取りする「プロセス間通信(IPC)」を実現する際に利用される特殊なファイルの一種です。
引数としては、作成するFIFOのパスを文字列型(string $filename)で指定します。次に、そのFIFOへのアクセス権限を八進数(例: 0666は誰もが読み書きできる権限)で整数型(int $permissions)として指定します。関数は、FIFOの作成に成功した場合はtrueを、失敗した場合はfalseをブール型(bool)で返します。
提供されたサンプルコードでは、まずposix_mkfifoを使ってFIFOを作成し、親プロセスと子プロセス(自身のスクリプトを別のPHPプロセスとして起動)がこのFIFOを介して通信する様子を示しています。具体的には、子プロセスがFIFOにデータを書き込み、親プロセスがFIFOからデータを読み取ります。さらに、親プロセスが受信したデータ量に応じて、posix_kill関数を使用して子プロセスに終了シグナル(SIGTERM)を送信し、プロセスの終了を制御する応用例も含まれています。
この機能は、LinuxやmacOSなどのPOSIX互換のオペレーティングシステムで利用可能であり、PHPの「posix」拡張機能が有効になっている必要があります。posix_mkfifoは、PHPで高度なプロセス間連携を構築する際に役立つ重要なツールです。
このコードは、PHPで名前付きパイプ(FIFO)を用いたプロセス間通信と、posix_killによるプロセス制御を示すものです。まず、この機能はLinuxやmacOSなどのPOSIX準拠OSと、PHPのposix拡張が有効な環境でのみ動作します。posix_mkfifoで作成したFIFOファイルは、スクリプト終了時に自動では削除されないため、必ずunlink関数で明示的に削除してください。削除を怠ると、不要なファイルが残り続けます。また、fopenでFIFOを開く操作は、読み書きする両プロセスが同時に開くまで処理がブロックされるため、デッドロックに注意が必要です。posix_killでプロセスにシグナルを送る際は、対象プロセスのPIDが正しいか十分に確認し、意図しないプロセスを停止させないよう細心の注意を払ってください。エラー発生時はposix_strerrorなどを活用し、原因を特定することが重要です。
PHP posix_mkfifo で名前付きパイプを作成する
1<?php 2 3/** 4 * posix_mkfifo関数の使用例。 5 * 6 * この関数は、名前付きパイプ(FIFO)を作成します。 7 * FIFOは、関連性のないプロセス間でデータを交換するための特殊なファイルです。 8 * 一方のプロセスがFIFOに書き込み、もう一方のプロセスがFIFOから読み取ります。 9 * 通常のファイルとは異なり、データは一時的に保存され、読み取られると消費されます。 10 */ 11function createAndRemoveFifo(): void 12{ 13 // FIFOファイルの名前を定義します。 14 // 一時ファイルとして扱うため、ユニークな名前を生成するのが一般的です。 15 // 例として、/tmp ディレクトリに作成します。 16 $fifoFilename = '/tmp/my_fifo_' . uniqid() . '.fifo'; 17 18 // FIFOファイルのパーミッションを設定します。 19 // 0666 は、所有者、グループ、その他すべてのユーザーが読み書きできることを意味します。 20 $permissions = 0666; 21 22 echo "FIFOファイル '{$fifoFilename}' を作成しようとしています...\n"; 23 24 // posix_mkfifo関数を使用して、名前付きパイプ(FIFO)を作成します。 25 if (posix_mkfifo($fifoFilename, $permissions)) { 26 echo "INFO: FIFOファイル '{$fifoFilename}' が正常に作成されました。\n"; 27 echo "INFO: これで、このFIFOファイルをプロセス間通信に使用できます。\n"; 28 29 // 注意: このサンプルではFIFOの作成と削除のみを行います。 30 // 実際の使用には、別のプロセス(または同じスクリプト内の別の部分)が 31 // このFIFOファイルに書き込んだり読み込んだりする処理が必要です。 32 33 // 作成したFIFOファイルをクリーンアップします。 34 // テスト目的の場合、スクリプト終了時に削除することが望ましいです。 35 if (unlink($fifoFilename)) { 36 echo "INFO: FIFOファイル '{$fifoFilename}' が正常に削除されました。\n"; 37 } else { 38 // unlinkが失敗した場合、その理由をPOSIXエラー情報から取得できます。 39 $errno = posix_get_last_error(); 40 $errorString = posix_strerror($errno); 41 echo "ERROR: FIFOファイル '{$fifoFilename}' の削除に失敗しました。詳細: {$errorString} (errno: {$errno})\n"; 42 } 43 44 } else { 45 // posix_mkfifoが失敗した場合、その理由をPOSIXエラー情報から取得します。 46 $errno = posix_get_last_error(); 47 $errorString = posix_strerror($errno); 48 echo "ERROR: FIFOファイル '{$fifoFilename}' の作成に失敗しました。詳細: {$errorString} (errno: {$errno})\n"; 49 } 50} 51 52// 関数を実行します。 53createAndRemoveFifo(); 54 55?>
posix_mkfifo関数は、PHPで名前付きパイプ(FIFO)を作成するために使用されます。FIFOは、関連性のない複数のプロセス間でデータをやり取りするための特殊なファイルの一種です。通常のファイルとは異なり、データは一時的に保存され、一方のプロセスが書き込み、もう一方のプロセスが読み取るとデータは消費されます。
この関数は、作成するFIFOファイルのパスと名前を文字列 $filename で、そしてそのファイルのパーミッションを整数 $permissions で指定します。パーミッションは、ファイルの読み書き権限などを設定するもので、例えば 0666 は所有者、グループ、その他のユーザーすべてに読み書き権限を与えることを意味します。関数の実行に成功すると true が、失敗した場合は false が戻り値として返されます。
サンプルコードでは、まず一時的なFIFOファイル名を生成し、それを /tmp ディレクトリに 0666 のパーミッションで作成しようとしています。posix_mkfifo関数が true を返せばFIFOの作成は成功し、プロセス間通信に利用可能となります。作成に失敗した場合、posix_get_last_error()とposix_strerror()を使ってエラーの詳細を取得し、原因を特定しています。作成に成功した後、このサンプルではテスト目的で unlink 関数を用いて作成したFIFOファイルを削除し、システムをクリーンアップしています。これにより、FIFOの作成から削除までの一連の流れを確認できます。
posix_mkfifoはPOSIXシステム専用で、Windowsでは動作しません。FIFOファイル名は重複を避けユニークに、セキュリティ考慮の適切なパーミッションを設定してください。戻り値で成否を確認し、失敗時はposix_get_last_error()でエラー原因を特定してください。使用後はunlink()で確実に削除し、リソースをクリーンアップしてください。サンプルは作成と削除の基本で、実際のプロセス間通信は別途実装が必要です。