如何通过PHP调用CLI脚本实现socket持续运行不中断
PHP代码调用CLI Socket脚本持续运行解决方案
问题本质
直接在终端执行CLI命令时,socket进程属于当前终端会话的独立进程,不受其他进程生命周期影响。通过PHP代码调用时,socket进程默认是调用方脚本的子进程,会受父进程退出、信号中断、执行超时、输出阻塞等因素影响异常终止。
具体实现方案
方案1:使用nohup后台执行(最常用)
调用时添加nohup指令、输出重定向和后台运行标记,让进程完全脱离父进程生命周期,命令如下:
nohup /usr/local/zend/bin/php-cli /app/test1/backend/scripts/scedjule/echoTestWebSocket.php > /app/logs/websocket.log 2>&1 &
参数说明:
nohup:忽略SIGHUP挂断信号,父进程退出时不会杀掉该子进程> /app/logs/websocket.log:将标准输出写入日志文件,也可写为> /dev/null丢弃输出2>&1:将错误输出合并到标准输出,避免输出缓冲区满导致进程阻塞&:让进程在后台运行,调用方无需等待进程返回
PHP代码中调用示例:
// 不要用shell_exec、passthru等会等待进程返回的函数,直接用exec即可 exec('nohup /usr/local/zend/bin/php-cli /app/test1/backend/scripts/scedjule/echoTestWebSocket.php > /app/logs/websocket.log 2>&1 &');
必备配置补充
- Socket脚本开头必须添加执行时间限制取消代码:
set_time_limit(0);,避免PHP默认30秒超时自动结束进程 - 若服务器开启pcntl扩展,可在socket脚本的事件循环前注册信号忽略,避免异常信号终止进程:
// 忽略挂断信号、管道断开信号 pcntl_signal(SIGHUP, SIG_IGN); pcntl_signal(SIGPIPE, SIG_IGN); // 循环内需要增加信号分发逻辑 while(true) { pcntl_signal_dispatch(); // 原有socket处理逻辑 } - 确认web运行用户(常见为www、nginx、apache)对socket脚本、日志目录、监听端口有足够权限,避免权限不足导致进程被系统终止。
方案2:使用systemd托管进程(稳定性更高)
如果需要长期运行、异常自动重启,可以将socket脚本配置为systemd系统服务,配置步骤:
- 新建服务配置文件
/etc/systemd/system/websocket.service,内容如下:
[Unit]
Description=Custom WebSocket Service
After=network.target[Service]
Type=simple替换为实际运行进程的用户User=www
ExecStart=/usr/local/zend/bin/php-cli /app/test1/backend/scripts/scedjule/echoTestWebSocket.php异常退出自动重启Restart=always
重启间隔3秒RestartSec=3
[Install]
WantedBy=multi-user.target
- 执行命令加载配置:
systemctl daemon-reload - PHP代码中调用服务管理命令即可控制进程:
// 启动服务 exec('systemctl start websocket.service'); // 停止服务 exec('systemctl stop websocket.service'); // 重启服务 exec('systemctl restart websocket.service');
配置后socket进程由系统托管,即使出现异常崩溃也会自动拉起,稳定性更高。
内容的提问来源于stack exchange,提问作者Hardiyana Hardiyana
相关产品推荐
相关产品推荐

