方式一:msg_get_queue实现
$key = ftok(__FILE__, 'a');
$queue = msg_get_queue($key);
$pidList = [];
$socketList = [];
for ($i = 1; $i <= 2; $i++) {
$taskPid = pcntl_fork();
if ($taskPid == -1) {
die("[父进程]child{$i}创建失败");
} elseif ($taskPid) {
$pidList[$i] = $taskPid;
echo "[父进程]child{$i}创建成功,子进程ID:{$taskPid}". PHP_EOL;
} else {
//子进程
while (true) {
msg_receive($queue, 1, $type, 1024, $msg);
if ($msg) {
echo "[子进程@child{$i}]收到消息:{$msg}";
}
usleep(50);
}
}
}
//父进程循环
while (true) {
msg_send($queue, 1, ['from'=>'father','text'=>"Hi child,I'm father."]);
sleep(3);
}
方式二:stream_socket_pair实现
$pidList = [];
$socketList = [];
for ($i = 1; $i <= 2; $i++) {
$sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
$mainSocket = $sockets[0];
$taskSocket = $sockets[1];
$taskPid = pcntl_fork();
if ($taskPid == -1) {
die("[父进程]child{$i}创建失败");
} elseif ($taskPid) {
fclose($mainSocket);
$pidList[$i] = $taskPid;
$socketList[$i] = $taskSocket;
echo "[父进程]child{$i}创建成功,子进程ID:" . $taskPid . PHP_EOL;
} else {
//子进程
while (true) {
$text = fgets($mainSocket);
if ($text) {
echo "[子进程@child{$i}]收到消息:" . $text;
}
usleep(50);
}
}
}
//父进程循环
while (true) {
foreach ($socketList as $i => $socket) {
fwrite($socket, "Hi child{$i},I'm father.\n");
}
sleep(3);
}
完整方案,优雅退出
$pidList = [];
$socketList = [];
for ($i = 1; $i <= 2; $i++) {
$sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
$mainSocket = $sockets[0];
$taskSocket = $sockets[1];
$taskPid = pcntl_fork();
if ($taskPid == -1) {
die("[父进程]child{$i}创建失败");
} elseif ($taskPid) {
fclose($mainSocket);
$pidList[$i] = $taskPid;
$socketList[$i] = $taskSocket;
echo "[父进程]child{$i}创建成功,子进程ID:" . $taskPid . PHP_EOL;
} else {
//子进程
fclose($taskSocket);
//子进程-开启异步信号处理
pcntl_async_signals(true);
pcntl_sigprocmask(SIG_BLOCK, [SIGTERM]);//阻塞SIGTERM信号
//子进程-注册退出信号
pcntl_signal(SIGQUIT, function () use ($mainSocket, $i) {
fclose($mainSocket);
echo "[子进程@child{$i}]收到退出信号,进程退出" . PHP_EOL;
exit();
});
while (true) {
$text = fgets($mainSocket);
if ($text) {
echo "[子进程@child{$i}]收到消息:" . $text;
}
usleep(50);
}
}
}
//父进程-开启异步信号处理
pcntl_async_signals(true);
pcntl_sigprocmask(SIG_BLOCK, [SIGTERM]);//阻塞SIGTERM信号
//父进程-注册退出信号
pcntl_signal(SIGQUIT, function () use ($socketList, $pidList) {
foreach ($socketList as $socket) {
fclose($socket);
}
echo '[父进程]收到退出信号,进程退出' . PHP_EOL;
system('kill -QUIT ' . implode(' ', array_values($pidList)));
foreach ($pidList as $pid) {
pcntl_wait($status);
}
exit();
});
while (true) {
foreach ($socketList as $i => $socket) {
fwrite($socket, "Hi child{$i},I'm father.\n");
}
sleep(3);
}
使用kill -QUIT命令向父进程发送退出信号
kill -QUIT 父进程ID
文章作者:DOTATONG
发布日期:2023-03-09
评论