workerman 不直接处理串口gps,仅接收网络数据;需设备支持tcp/udp上报或经串口转网桥接;收到后须按nmea规范校验、分包、过滤$gprmc行解析。

Workerman 本身不直接处理串口或硬件 GPS 模块,它只负责 TCP/UDP 网络层通信。如果你的 GPS 定位器是通过串口(如 USB 转串口)直连服务器,必须先用其他方式(比如 Python 脚本、C 程序或串口透传网关)把串口数据转成网络包发给 Workerman;如果定位器自带 TCP/UDP 上报功能(常见于 4G 物联网 GPS 终端),那 Workerman 就能直接收 —— 这才是它能“解析”的前提。
GPS 数据怎么进 Workerman:必须走网络协议
Workerman 的 onMessage 回调只触发于收到网络数据包时,它不会监听 /dev/ttyUSB0 或 COM3。所以你要确认 GPS 设备的输出路径:
- 设备支持 TCP 主动连接(如配置为 “TCP Client”,目标 IP 是你的 Workerman 服务器地址 + 端口)→ 可直接收
- 设备只输出串口 NMEA(如 $GPRMC,...)→ 必须加一层串口转 TCP 的桥接(例如用
ser2net、python -m serial.tools.miniterm+ 自写转发脚本,或专用透传模块) - 设备通过 HTTP POST 上报 → 那该用 Workerman 的
WebServer模式,而不是TcpConnection
漏掉这步,直接在 onMessage 里写解析逻辑,永远等不到数据。
收到原始字节后,怎么安全提取 $GPRMC 行
GPS 终端常连续发送多条 NMEA 语句($GPGGA、$GPRMC、$GPGSV),且可能粘包、断包。不能直接 explode("\n", $data),得按行边界 + 校验和过滤:
- 用
substr($data, 0, 1) === '$'判断是否为 NMEA 行起始 - 用
strpos($data, "\r\n") !== false或strpos($data, "\n") !== false找行尾(不同设备换行符不同) - 对每行做校验和验证:取
$后到*前所有字符异或,再与*xx的十六进制值比对(否则可能解析脏数据) - 只保留
substr($line, 0, 6) === '$GPRMC'的行,跳过$GPGLL等无关语句
示例片段(放在 onMessage 中):
if (strpos($data, '$GPRMC') !== false) {
$lines = preg_split('/\r\n|\r|\n/', $data);
foreach ($lines as $line) {
if (strlen($line) <h3>解析 $GPRMC 字段时最常踩的坑</h3><p>字段顺序固定但空字段存在(如磁偏角为空导致 <code>$GPRMC,...,150706,,,A*50</code>),直接 <code>explode(',', $line)</code> 后取 <code>$parts[9]</code> 会错位:</p>
- 必须用
str_getcsv($line)(PHP 5.3+),它能正确处理空字段(,,→['a','','c']) -
$parts[2]是状态:仅当值为'A'才代表有效定位,'V'表示无效,别直接转坐标 - 经纬度是度分格式(
ddmm.mmmm),不是十进制度:需拆substr($parts[3], 0, 2)为度,substr($parts[3], 2)为分,再算$deg + $min / 60 - UTC 时间
$parts[1]是hhmmss.sss,日期$parts[9]是ddmmyy,拼成完整时间需注意年份(230394→ 2023 年 3 月 24 日?还是 2094 年?得结合上下文或系统时钟判断)
没做空字段兼容或校验和验证,解析出的经纬度可能是上一条错误语句的残留值,位置漂移几百米都算轻的。
真正难的从来不是写几行 explode,而是让解析器在弱网、断电重连、设备固件 bug 导致乱码的现场持续稳住 —— 校验和、字段长度防御、状态标记、日志埋点,一个都不能少。











