当前位置:首页 > 文章列表 > 文章 > php教程 > PHP stream_socket_pair 怎么让父子进程双向传递消息

PHP stream_socket_pair 怎么让父子进程双向传递消息

来源:17golang原创 2026-11-05 13:47:16 0浏览 收藏

先用 stream_socket_pair 创建两个相连的本地socket流,再调用 pcntl_fork。父进程保留端点0、关闭端点1,子进程保留端点1、关闭端点0;两边保留的端点都能读写。再约定父进程先发请求、子进程读完后回复,就能完成一次双向通信。

官方地址:https://www.php.net/manual/en/function.stream-socket-pair.php

先确认是CLI父子进程通信

遇到“父进程发了消息,子进程没有反应”时,我会先看运行环境和协议约定,而不是先加入sleep。本文采用Unix类系统CLI、PCNTL和阻塞流的小消息场景;代码使用PHP 8字符串函数,不适合作为Windows父子进程方案直接照搬,也不应直接放进普通Web请求处理流程。

这里没有监听端口、接受连接或连接远端服务器。pair在fork之前创建,父子进程继承连接资源。若各自在fork之后创建一对socket,得到的是两套独立连接,不能据相同数组下标建立通信。

把两个端点分别交给父进程与子进程

两个端点是对等的,下标只用于本例分工,不是“读端”和“写端”。父端写出的数据由子端读取,子端写出的数据由父端读取。fork以后双方都会暂时持有两个端点,应立即关闭各自不用的那个。

关闭多余端点有两个用途:减少资源占用,让连接的结束语义更明确。仍有进程持有某个端点时,另一侧等待EOF可能与预期不同。不能只在PHP变量层面说“不使用”,而不实际关闭资源。

父子进程保留和关闭socket端点的关系
图1:端点归属结构说明图。父进程保留0,子进程保留1,两个保留端点均可双向读写。

用换行协议完成一次请求和应答

流式socket承载字节,不为每次fwrite保存应用消息边界。下面用换行分隔,限制单条消息,并循环处理短写。示例只发送短文本,预期应答内容为 ack:task-42,这不是本文实际运行输出。

 4096) {
        throw new RuntimeException('消息格式不符合约定');
    }
    $wire = $message . "\n";
    $offset = 0;
    while ($offset getMessage() . PHP_EOL);
        $exitCode = 1;
    } finally {
        fclose($child);
    }
    exit($exitCode); // 子进程不继续执行父进程分支。
}

fclose($pair[1]); // 父进程只保留端点0,同一端点可以读也可以写。
$parent = $pair[0];
$reply = null;
$failure = null;
try {
    if (!stream_set_timeout($parent, 5)) {
        throw new RuntimeException('设置读取超时失败');
    }
    sendLine($parent, 'task-42'); // 父进程先写,避免双方都等待读取。
    $reply = receiveLine($parent);
} catch (Throwable $e) {
    $failure = $e;
} finally {
    fclose($parent);
    // 关闭端点后回收子进程;信号中断时继续等待。
    do {
        $waited = pcntl_waitpid($pid, $status);
    } while ($waited === -1 && pcntl_get_last_error() === PCNTL_EINTR);
}

if ($failure !== null) {
    throw $failure;
}
if ($waited !== $pid || !pcntl_wifexited($status)
    || pcntl_wexitstatus($status) !== 0) {
    throw new RuntimeException('子进程未正常结束');
}
echo $reply, PHP_EOL;

这里把数据写入、读到完整应答、子进程正常退出分别判断。写入成功只表示字节交给流,不表示对方已经处理;收到应答才体现这一轮协议完成。

示例的4096字节限制是教学选择。子进程在载荷前添加 ack:,所以接近长度上限的请求可能使应答超限并进入错误路径;业务设计应同时计算请求和应答的最大尺寸。任意二进制或多行消息更适合长度前缀协议,本例不扩展这部分。

卡住或读到半条消息时检查什么

现象先检查对应处理
双方都停在读取是否双方都先fgets指定一方先发送
消息有内容却不返回是否缺少换行保证消息结束符完整
只传了部分内容fwrite返回的字节数继续写剩余字节,0或false进入错误路径
读到片段却误认为成功是否确实有完整结束符拒绝不完整帧,不当正常消息使用
等待EOF没有结束多余端点是否仍被持有关闭每个进程不用的端点

五秒超时只用于帮助这个短消息示例识别读取异常,不是整个父子进程生命周期的硬截止时间。实际应用若子进程可能陷入业务计算,需要额外的生命周期管理;父进程的waitpid不会因为流的读取超时自动结束等待。

双方先写大量数据也可能因缓冲区容量而阻塞。这个请求应答示例没有实现大消息并发收发,也没有非阻塞事件循环;不能只把字符串放大就认为能保持同样行为。

行消息的发送读取和错误处理组成
图2:消息协议结构说明图。换行、长度约束、完整写入与完整读取共同定义一条消息,不表示执行记录。

把端点关闭与子进程回收一起收尾

子进程需要在自己的分支关闭端点并退出,父进程关闭端点后还要回收子进程。通信资源的关闭与进程状态回收属于不同工作:fclose不能替代waitpid,waitpid也不能替代消息是否完整的判断。

我会保留四个最小约定:端点归属固定、消息边界明确、读写顺序一致、异常后能够关闭和回收。它们能让短消息通信的行为更容易解释,比依赖任意休眠时间更可靠。

一定要两对socket才能双向通信吗?不用。一对相连的流式socket两侧都能读写。

收到EOF算一条成功消息吗?本例不算。只有带换行的完整消息才成功,EOF前的残缺内容进入错误路径。

可以先waitpid再读应答吗?不适合盲目这样做。子进程可能等待父进程读取才能完成写入,父进程却在等待它退出,形成互等。

参考:stream_socket_pair;pcntl_fork;fwrite;fgets;pcntl_waitpid。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
OpenTelemetry Kubernetes 事件怎样关联到发布批次OpenTelemetry Kubernetes 事件怎样关联到发布批次
上一篇
OpenTelemetry Kubernetes 事件怎样关联到发布批次
CNCF 云原生 AI 应用怎样划分平台与业务边界
下一篇
CNCF 云原生 AI 应用怎样划分平台与业务边界
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    893次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    895次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    979次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    968次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    793次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码