PHP 多進程協作可透過命名管道實現進程間通信(IPC)。管道本質為先進先出佇列,預設容量 4KB,預設阻塞模式(寫滿阻塞、讀空阻塞),可用 stream_set_blocking 設為非阻塞。
<?php
class Pipe {
public $fifoPath;
private $w_pipe;
private $r_pipe;
/**
* 建立命名管道
* @param string $name 管道名稱
* @param int $mode 權限(預設 0666)
*/
public function __construct($name = 'pipe', $mode = 0666) {
$this->fifoPath = "/tmp/$name." . posix_getpid();
if (!file_exists($this->fifoPath)) {
if (!posix_mkfifo($this->fifoPath, $mode)) {
trigger_error("create pipe ($name) failed", E_USER_ERROR);
return false;
}
} else {
trigger_error("pipe ($name) already exists", E_USER_WARNING);
return false;
}
}
// ===== 寫入相關 =====
public function open_write() {
$this->w_pipe = fopen($this->fifoPath, 'w');
return $this->w_pipe !== false;
}
public function write($data) {
return fwrite($this->w_pipe, $data);
}
public function write_all($data) {
$fp = fopen($this->fifoPath, 'w');
fwrite($fp, $data);
fclose($fp);
}
public function close_write() {
return fclose($this->w_pipe);
}
// ===== 讀取相關 =====
public function open_read() {
$this->r_pipe = fopen($this->fifoPath, 'r');
return $this->r_pipe !== false;
}
public function read($byte = 1024) {
return fread($this->r_pipe, $byte);
}
public function read_all() {
$fp = fopen($this->fifoPath, 'r');
$data = '';
while (!feof($fp)) {
$data .= fread($fp, 1024);
}
fclose($fp);
return $data;
}
public function close_read() {
return fclose($this->r_pipe);
}
// 刪除管道
public function rm_pipe() {
return unlink($this->fifoPath);
}
}
?>
// 父進程建立管道
$pipe = new Pipe('myipc');
$pid = pcntl_fork();
if ($pid == -1) die('fork failed');
if ($pid == 0) {
// 子進程:讀取管道
$pipe->open_read();
echo "Child received: " . $pipe->read_all() . "\n";
$pipe->close_read();
$pipe->rm_pipe();
exit;
} else {
// 父進程:寫入管道
$pipe->open_write();
$pipe->write("Hello from parent!\n");
$pipe->close_write();
pcntl_wait($status);
}
/tmp,以 PID 區分,避免衝突。posix_mkfifo 需啟用 POSIX 擴展(Linux/Unix 環境)。fopen('w') 會阻塞直到有讀端開啟;fopen('r') 會阻塞直到有寫端開啟。