frame协议与text协议的本质区别在于数据边界识别方式不同:text协议依赖换行符\r\n切分消息,frame协议依靠固定长度头部(如前2字节存payload长度)标记帧边界,因此frame协议可安全传输含\r\n的二进制数据,而text协议不可。

Frame协议和Text协议的本质区别在哪
根本不在“传输效率”或“流量大小”,而在于**数据边界识别方式不同**:Text协议靠换行符 \r\n 切分消息,Frame协议靠固定长度头(如前2字节存payload长度)标记帧边界。这意味着——Text协议天然无法安全传输含 \r\n 的二进制数据(比如图片、加密密文),而Frame协议可以。
什么时候必须用Frame协议,不能用Text协议
当你需要可靠传输以下内容时,Text协议会出问题:
- 任意二进制数据(如传感器原始采样值、JPEG缩略图、Protobuf序列化结果)
- 用户输入中可能含
\r\n的文本(比如粘贴的日志片段、JSON字符串) - 服务端需严格按“一帧一处理”做原子操作(如指令+校验和打包成一帧)
典型场景:物联网设备上报、音视频流分片、自定义RPC协议。用Text协议在这种场景下会出现粘包、截断、解析错位——input 回调拿到的 buffer 可能是半帧或两帧拼接体,且无法无损还原原始字节。
Workerman/GatewayWorker里怎么写正确的Frame协议input
以常见2字节大端长度头为例(即前2字节表示后续数据长度),Protocols 类的 input 必须返回完整帧长度(含头部),否则框架无法切帧:
public static function input($buffer, $connection)
{
if (strlen($buffer) = $total ? $total : 0; // 返回0表示不完整,继续收
}
常见错误:
- 忘了加头部长度(只返回
$len),导致框架永远收不满 - 用
unpack('S')(小端)但设备发的是大端,解析出错长度 - 没检查
strlen($buffer) 就直接 unpack,PHP报 warning 并返回 false
Text协议看似简单,但实际容易掉坑
很多人以为 Text 协议就是 explode("\r\n", $buffer),但真实网络中:
- TCP是流式传输,
\r\n可能被拆在两个 TCP 包里,input一次收不到完整行 - 有些设备用
\n换行,有些用\r\n,协议不统一就丢数据 - 空行(连续
\r\n\r\n)在 HTTP 风格协议里有特殊含义,但纯 Text 协议里它只是个合法消息
所以哪怕选 Text 协议,也得在 input 里做缓冲 + 行查找,不能假设单次 $buffer 必然含完整行——这点和 Frame 协议的“定长头+校验”思路完全不同,也更难写稳。
真正省事的从来不是协议类型,而是你是否清楚每一字节从哪来、到哪去、中间谁动过它。











