根本原因是串口流默认阻塞,需用stream_set_blocking($fp, false)设为非阻塞;之后用fread()读取并配合usleep(10000)防忙等,避免popen/fgets方案,并手动实现Modbus等上层协议帧解析。
PHP 读 RS485 设备时卡住(比如 fgets() 一直不返回),根本原因不是“RS485 协议问题”,而是串口文件描述符默认处于阻塞模式——只要没收到完整数据,读操作就挂起整个 PHP 进程。解决它,必须显式启用非阻塞 I/O。
stream_set_blocking() 设置串口为非阻塞PHP 操作串口(如 /dev/ttyUSB0)本质是打开一个流资源,而非直接调用系统 socket。不能用 fcntl() 或 ioctl(),必须使用 PHP 原生流控制函数:
stream_set_blocking($fp, false) 是唯一可靠方式;设为 false 后,fread()、fgets() 等读取函数在无数据时立即返回空字符串(""),而不会等待fopen() 打开串口后、任何读写前调用,顺序错误会导致设置失效启用非阻塞后,不能直接 while (fgets($fp)) { ... }——这会瞬间跑满 CPU。必须加条件控制或延时:
$data = fread($fp, 256); if ($data === false || $data === '') { usleep(10000); continue; }
usleep(0) 或空 continue:某些内核版本下会退化为忙等,usleep(10000)(10ms)是较安全的底线stream_select() 使用,单纯靠 usleep() 无法精准计时popen() + fgets() 在 RS485 场景中大概率失
败很多开发者试图用 popen('stty -F /dev/ttyUSB0 9600 raw -echo; cat /dev/ttyUSB0', 'r') 绕过 PHP 串口限制,但这会引入严重问题:
cat 默认按行缓冲,而 RS485 报文无换行符,fgets() 会永远等不到 \n,实际仍是逻辑阻塞\0 字节(fgets() 遇到 \0 就截断),Modbus/RTU 帧里常见该字节fopen() + stream_set_blocking() + fread(),配合 stream_set_timeout() 控制单次读最大等待时间真正容易被忽略的是:非阻塞只是“不卡住”,不代表“自动组帧”。RS485 是物理层,上层协议(如 Modbus RTU)的帧头识别、长度解析、CRC 校验仍需你手动实现;否则即使读到了字节,也可能是半帧或粘包数据。
# php
# linux
# 字节
# usb
# stream
# 为什么
# echo
# if
# while
# fopen
# fgets
# continue
# 字符串
# 循环
# 串口
# 设为
# 这会
# 根本原因
# 的是
# 不代表
# 仍是
# 不能用
# 而非
# 读到
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
网络优化76771 】
【
技术知识130152 】
【
IDC云计算60162 】
【
营销推广131313 】
【
AI优化88182 】
【
百度推广37138 】
【
网站推荐60173 】
【
精选阅读31334 】
相关推荐:
短链接还原php提示内存不足_调整PHP内存限制设置【技巧】
Go语言中CookieJar的持久化机制解析:内存存储与自定义持久化方案
Win11相机打不开提示错误怎么修_相机权限开启与驱动修复【影像修复】
Win11怎样安装搜狗输入法_Win11安装搜狗输入法教程【步骤】
静态属性修改会影响所有实例吗_php作用域操作符下静态存储【教程】
c++中explicit(bool)的用法 c++条件性explicit【C++20】
如何在 Go 项目开发中正确处理本地包导入与远程模块路径的一致性问题
如何在Golang中实现自定义Benchmark_Golang testing.B自定义性能测量示例
C#如何使用XPathNavigator高效查询XML
Python列表推导式与字典推导式教程_简化代码高效写法
如何使用Golang实现文件追加操作_向已有文件追加数据
php怎么连接数据库_MySQL数据库连接的基础代码编写【说明】
Windows服务无法启动错误1067是什么_进程意外终止的解决方法
Go 中的 := 运算符:类型推导机制与使用边界详解
Win11如何卸载OneDrive_Win11卸载OneDrive方法【教程】
Windows如何拦截腾讯视频广告_Windows拦截腾讯视频广告方法【方法】
如何在 Go 中正确初始化结构体中的 map 字段
如何在Golang中验证模块完整性_Golanggo.sum校验与安全实践
C++友元类使用场景_C++类间协作设计方式讲解
php串口通信波特率怎么选_根据硬件手册设置正确波特率【方法】
Win11怎么卸载Photos应用_Win11卸载Photos应用方法【教程】
如何在 Go 中正确反序列化多个同级 XML 元素(而非单个根节点)
Win11怎么设置多显示器任务栏 Win11扩展任务栏至多屏方便跨屏操作【技巧】
如何使用Golang实现函数指针_函数变量与回调示例
Win11怎么更改输入法顺序_Win11调整语言首选位置【设置】
C++如何获取CPU核心数?(std::thread::hardware_concurrency)
Win11开机自检怎么关闭_跳过Win11开机磁盘扫描修复方法【技巧】
Windows 11登录时提示“用户配置文件服务登录失败”怎么办_Windows 11修复损坏的用户配置文件
Win11怎么关闭通知中心_Windows11系统通知与专注助手设置
Linux如何安装JDK11_Linux环境变量配置与Java开发环境搭建【教程】
Win11怎么关闭定位服务 Win11禁止应用获取位置信息【隐私】
如何使用Golang defer优化性能_减少不必要的函数调用
如何使用Golang table-driven基准测试_多组数据测量函数效率
Windows怎样拦截QQ浏览器广告_Windows拦截QQ浏览器广告方法【方法】
Laravel 查询 JSON 列:高效筛选包含数组中任意值的记录
Windows10如何更改鼠标灵敏度_Win10鼠标属性指针选项调节
Python数据挖掘进阶教程_分类回归与聚类案例解析
Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】
Win11怎么关闭OneDrive同步_Win11取消自动备份文件【教程】
Windows系统文件被保护机制阻止怎么办_权限不足错误处理方案
Win11怎么关闭自动维护 Win11禁用系统自动维护功能【优化】
Win11怎么把图标拖到任务栏_Win11固定应用快捷方式指南【方法】
如何使用Golang log记录不同级别日志_Golang log Println与Fatal示例
c++中如何计算坐标系中两点间距离_c++勾股定理求距离
php会话怎么开启_session_start函数的作用与使用时机【方法】
如何在 Python 测试中动态配置 @backoff 装饰器的重试次数
Mac怎么安装软件_Mac安装dmg与pkg文件的区别【指南】
MAC如何修改默认应用程序_MAC文件后缀关联设置与打开方式更改【教程】
Python与MongoDB NoSQL开发实战_文档模型与索引优化
如何在Golang中处理模块冲突_解决依赖版本不兼容问题
2026-01-01
致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。