PHP通过proc_open启动cu命令读取GSM调制解调器输出时fread挂起问题
问题原因
cu 属于交互式终端工具,默认交互场景下的状态输出(比如 Connected. 提示)是直接输出到控制终端(TTY),而非标准输出(STDOUT)或标准错误(STDERR)。你通过 proc_open 创建的管道不属于 TTY 设备,所以这部分输出根本没有进入你监听的 $pipes[1] 管道,自然读不到内容,导致阻塞。
而 cu -v 属于非交互的版本查询场景,输出直接写 STDOUT,所以可以正常通过管道读取。
解决方案
- 方案1:使用伪终端(PTY)替代管道
proc_open支持指定 PTY 类型的描述符,模拟终端环境让 cu 正常输出内容,修改代码如下:
<?php $descriptors = [ 0 => ['pty', 'r'], 1 => ['pty', 'w'], 2 => ['file', 'errors.txt', 'a'] ]; $handle = proc_open('cu -s 115200 -l /dev/ttyUSB3', $descriptors, $pipes); stream_set_blocking($pipes[1], 1); $world = fread($pipes[1], 1); var_dump($world);
注意:运行PHP脚本的用户需要拥有 /dev/ttyUSB3 的读写权限,建议将用户加入 dialout 用户组。
- 方案2:直接操作串口设备(更推荐)
不需要额外依赖 cu 工具,直接通过PHP读写串口设备,稳定性更高。
首先通过 stty 配置串口参数:stty -F /dev/ttyUSB3 115200 cs8 -cstopb -parenb
之后直接在PHP中操作:
<?php $serial = fopen('/dev/ttyUSB3', 'r+'); stream_set_blocking($serial, 1); // 可直接发送AT指令调试 fwrite($serial, "AT\r\n"); echo fread($serial, 1024);
- 方案3:通过expect封装调用
expect 工具天生适配交互式程序,会自动创建伪终端,你可以编写expect脚本捕获cu的输出,再通过PHP调用expect脚本获取结果。
内容的提问来源于stack exchange,提问作者Iain Dooley
相关产品推荐
相关产品推荐

