乐于分享
好东西不私藏

源码加更03_TCP 封装和基础编解码为什么决定稳定性

源码加更03_TCP 封装和基础编解码为什么决定稳定性

源码加更03_TCP 封装和基础编解码为什么决定稳定性

[!abstract] 这一篇完整公开 TCP 读写封装、Remaining Length 编解码、字符串和载荷拼接。它是 MQTT 报文能否稳定落到 PLC 缓冲区的基础。

适合谁收藏

  • 正在处理 TCP 粘包、半包、读写失败和缓冲区问题的工程师。
  • 想把 MQTT Remaining Length 从规范条文落到 ST 代码的读者。
  • 需要判断“报文错”和“传输层错”边界的人。

本篇核心图

读图重点:先看源码对象之间的职责边界,再看数据、状态和错误如何沿着调用链流动。源码加更不是把文件名列出来,而是把完整代码、工程意图和验证口径一起讲清楚。

先给结论

TCP 层只管字节通道,MQTT 层要自己判断完整报文、载荷长度和缓冲区边界。这层写不稳,上面所有 QoS 都会变成假稳定。

从理论到代码实现链路

MQTT 标准给的是报文类型、固定头、可变头、载荷、QoS 交互和会话语义;PLC 工程真正要解决的是周期扫描、缓冲区长度、错误锁存、在线变量、连接重入和现场可诊断性。

所以这套开源实现不能只按协议章节拆,也不能只按文件名拆。正确读法是把标准约束翻译成程序对象:入口程序负责给命令和观测点,GVL 和 DUT 定义容量与数据模型,主功能块负责调度状态机,构建方法负责出站报文,处理方法负责入站报文,辅助方法负责长度、队列、事务、主题和诊断边界。

本篇完整公开 TCP 封装、Remaining Length 工具、字符串载荷拼接和读缓冲方法。

再往下一层看,这里其实有两条线同时存在。第一条是协议线:固定头、Remaining Length、PacketId、QoS、Topic、Payload 和 Reason Code 必须能按 MQTT 规则组合起来。第二条是 PLC 工程线:每个周期只能推进有限步骤,所有中间状态都要能被在线变量观察,所有错误都要能被锁存并归类,所有缓冲区长度都要在写入前被检查。

这就是源码加更必须完整公开的原因。只给几段核心片段,读者最多能看懂某个判断;把完整对象放出来,读者才能看到对象之间如何传递状态、长度、错误和诊断信息。完整源码讲解不是为了堆代码,而是为了让读者能从标准约束一路追到可运行的 ST 对象,再从现场现象反向定位到具体边界。

本篇公开的完整源码范围

序号
源码对象
讲解重点
1
FB_MqttClient.M_TcpClient.st
TCP 读写封装,隔离字节通道和 MQTT 状态机
2
FB_MqttClient.M_TcpRead.st
TCP 读写封装,隔离字节通道和 MQTT 状态机
3
FB_MqttClient.M_TcpWrite.st
TCP 读写封装,隔离字节通道和 MQTT 状态机
4
FB_EncodeRemainingLength.st
源码对象职责和验证边界
5
FB_DecodeRemainingLength.st
源码对象职责和验证边界
6
M_EncodeRemainingLength.st
源码对象职责和验证边界
7
M_DecodeRemainingLength.st
源码对象职责和验证边界
8
M_AppendString.st
源码对象职责和验证边界
9
M_AppendPayload.st
源码对象职责和验证边界
10
M_CopyBytesToString.st
源码对象职责和验证边界
11
M_ReadIntoBuffer.st
源码对象职责和验证边界
12
M_IsValidUtf8String.st
源码对象职责和验证边界

怎么读这些源码

第一遍只看对象职责:这个文件解决哪一层问题,是入口、模型、状态、构建、接收、事务,还是诊断。

第二遍看边界变量:长度、索引、PacketId、QoS、状态枚举、错误码、缓冲区水位和在线观测量。PLC 通信代码最怕的是“能跑但不可诊断”,所以每个关键对象都要问一句:现场出问题时,我能不能从它留下的变量看出原因。

第三遍再看具体语句。源码全部公开,不等于读者要从第一行顺序读到最后一行。更稳的方式是用图和表先建立地图,再回到完整代码里确认每个边界确实落地。

工程验证路径

用抓包和在线变量对照:TCP 读到的字节数、Remaining Length 解码结果、有效载荷长度和字符串转换结果必须一致。

本篇完整开源代码

完整代码 1:FB_MqttClient.M_TcpClient.st

这一段完整公开 FB_MqttClient.M_TcpClient.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_TcpClient/// 功能      : 控制 TCP 客户端的连接与断开/// 说明      : 封装 NBS TCP 客户端连接调用,输出连接状态与错误信息。/// 编程人员  : ControlRookie/// 时间      : 2026-01-10/// 版本      : V1.1/// ======================================================================={attribute 'hide_all_locals'}METHOD M_TcpClientVAR_INPUT    bEnable                : BOOL;           // TCP 连接使能标志    sIP                    : STRING;         // 服务器 IP 地址    uiPortNum              : UINT;           // 目标 Broker 提供 MQTT 服务的监听端口号END_VARVAR_OUTPUT    bIsConnected           : BOOL;           // 连接成功标志    bError                 : BOOL;           // 错误标志    eError                 : NBS.ERROR;      // NBS 错误码END_VARVAR    stIP                   : NBS.IP_ADDR;    // 服务器地址结构END_VAR// === IMPLEMENTATION ===// 把字符串地址先转成 NBS 需要的地址结构,再交给底层 TCP_Client。stIP.sAddr := sIP;fbTcpClient(    xEnable     := bEnable,    ipAddr      := stIP,    uiPort      := uiPortNum,    eError      => eError,    hConnection => hConnection);// 统一把底层错误状态透传到上层状态机。bError := fbTcpClient.xError;// 只有底层已经 active 且句柄有效时,才认为 TCP 连接真正建立成功。IF fbTcpClient.xActive AND fbTcpClient.hConnection <> 0 THEN    bIsConnected := TRUE;ELSE    bIsConnected := FALSE;END_IF

完整代码 2:FB_MqttClient.M_TcpRead.st

这一段完整公开 FB_MqttClient.M_TcpRead.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_TcpRead/// 功能      : 从 TCP 连接读取数据到接收缓冲区/// 说明      : 封装 NBS.TCP_Read,读取成功后输出完成标志和实际字节数。/// 编程人员  : ControlRookie/// 时间      : 2026-05-05/// 版本      : V1.2/// ======================================================================={attribute 'hide_all_locals'}METHOD M_TcpReadVAR_INPUT    bEnable        : BOOL;            // TCP 读取使能标志    pDataReceive   : POINTER TO BYTE; // 接收数据区首地址    udiDataSize    : UDINT;           // 本次允许写入接收缓冲区的最大字节数[byte]END_VARVAR_OUTPUT    bDone          : BOOL;            // 读取完成标志    bError         : BOOL;            // 错误标志    eError         : NBS.ERROR;       // NBS 错误码    udiBytesRead   : UDINT;           // 本次实际从 TCP 连接读取的字节数[byte]END_VAR// === IMPLEMENTATION ===// 每周期持续调用底层 TCP_Read,是否真的读由 bEnable 控制。fbTcpRead(    xEnable      := bEnable,    xError       => bError,    hConnection  := hConnection,    szSize       := udiDataSize,    pData        := pDataReceive,    eError       => eError);// 只有底层声明 ready 且无错误时,才把本次读取结果上报给上层状态机。IF fbTcpRead.xReady AND NOT fbTcpRead.xError THEN    bDone := TRUE;    udiBytesRead := TO_UDINT(fbTcpRead.szCount);ELSE    bDone := FALSE;    udiBytesRead := 0;END_IF// 关闭读取使能时,显式把完成标志和本次字节数清零,避免上层误判复用旧结果。IF NOT bEnable THEN    bDone := FALSE;    udiBytesRead := 0;END_IF

完整代码 3:FB_MqttClient.M_TcpWrite.st

这一段完整公开 FB_MqttClient.M_TcpWrite.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_TcpWrite/// 功能      : 向 TCP 连接发送缓冲区数据/// 说明      : 包装 NBS.TCP_Write,发送成功后置位完成标志。/// 编程人员  : ControlRookie/// 时间      : 2026-05-05/// 版本      : V1.1/// ======================================================================={attribute 'hide_all_locals'}METHOD M_TcpWriteVAR_INPUT    bExecute               : BOOL;              // TCP 写入执行标志    pDataSend              : POINTER TO BYTE;   // 发送数据区首地址    udiDataSize            : UDINT;             // 本次计划发送的字节数[byte]END_VARVAR_OUTPUT    bDone                  : BOOL;              // 发送完成标志    bError                 : BOOL;              // 错误标志    eError                 : NBS.ERROR;         // NBS 错误码END_VAR// === IMPLEMENTATION ===// 每周期持续调用底层 TCP_Write,是否真正触发发送由 bExecute 控制。fbTcpWrite(    xExecute     := bExecute,    xError       => bError,    hConnection  := hConnection,    szSize       := udiDataSize,    pData        := pDataSend,    eError       => eError);// 发送脉冲撤销时立即清掉完成锁存,确保下一次发送重新形成独立 done 事件。IF NOT bExecute THEN    bWriteDoneLatched := FALSE;ELSIF fbTcpWrite.xError THEN    bWriteDoneLatched := FALSE;ELSIF fbTcpWrite.xDone THEN    // xDone 只要出现一次就锁存住,交给上层状态机在下一拍读取。    bWriteDoneLatched := TRUE;END_IFbDone := bWriteDoneLatched;

完整代码 4:FB_EncodeRemainingLength.st

这一段完整公开 FB_EncodeRemainingLength.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : FB_EncodeRemainingLength/// 功能      : 编码 MQTT 剩余长度字段/// 说明      : 将载荷长度编码为 MQTT 可变字节整数格式/// 编程人员  : ControlRookie/// 时间      : 2026-01-10/// 版本      : V1.1/// ======================================================================={attribute 'hide_all_locals'}FUNCTION_BLOCK FB_EncodeRemainingLengthVAR_INPUT    uiNumberOfBytes           : UINT;                  // 待写入报文头的 MQTT 剩余长度[byte]END_VARVAR_OUTPUT    iEncodedBytesCount        : INT;                   // MQTT 剩余长度编码结果的字节数[byte]    aEncodedBytes             : ARRAY[0..3] OF BYTE;  // MQTT 剩余长度编码结果缓冲区[byte]END_VARVAR    byEncodedByte             : BYTE;                  // 当前编码字节    uiTemp                    : UINT;                  // 中间长度变量    bContinue                 : BOOL;                  // 是否继续编码下一个字节END_VAR// === IMPLEMENTATION ===// Remaining Length 采用 MQTT 可变字节整数编码:// 每个字节低 7 位承载数值,最高位表示“后面还有没有后续字节”。uiTemp := uiNumberOfBytes;iEncodedBytesCount := 0;REPEAT    byEncodedByte := TO_BYTE(uiTemp MOD 128);    uiTemp := uiTemp / 128;    // 只要后面还有剩余数值,就把续位标志位置 1。    IF uiTemp > 0 THEN        byEncodedByte := byEncodedByte OR 16#80;        bContinue := TRUE;    ELSE        bContinue := FALSE;    END_IF;    aEncodedBytes[iEncodedBytesCount] := byEncodedByte;    iEncodedBytesCount := iEncodedBytesCount + 1;    // MQTT 标准规定 Remaining Length 最多只允许编码成 4 个字节。    IF iEncodedBytesCount >= 4 THEN        bContinue := FALSE;    END_IF;UNTIL (NOT bContinue)END_REPEAT;

完整代码 5:FB_DecodeRemainingLength.st

这一段完整公开 FB_DecodeRemainingLength.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : FB_DecodeRemainingLength/// 功能      : 解码 MQTT 剩余长度字段/// 说明      : 将 MQTT 可变字节整数格式解码为实际长度值/// 编程人员  : ControlRookie/// 时间      : 2026-01-10/// 版本      : V1.1/// ======================================================================={attribute 'hide_all_locals'}FUNCTION_BLOCK FB_DecodeRemainingLengthVAR_INPUT    pEncodedBytes             : POINTER TO BYTE;       // 指向 MQTT Remaining Length 编码起始字节的缓冲区指针END_VARVAR_OUTPUT    uiDecodedLength           : UINT;                  // 解码得到的 MQTT 剩余长度[byte]    uiBytesUsed               : UINT;                  // 解码该长度字段实际消耗的字节数[byte]    bDone                     : BOOL;                  // 解码是否成功END_VARVAR    uiMultiplier              : UINT := 1;            // 可变字节整数权重    uiValue                   : UINT := 0;            // 解码中间值    byByte                    : BYTE;                 // 当前读取字节    pCurrent                  : POINTER TO BYTE;      // 当前读取指针    uiCount                   : UINT := 0;            // 当前已读取的编码字节数[byte]END_VAR// === IMPLEMENTATION ===// Remaining Length 采用 MQTT 的可变字节整数编码,最多 4 个字节。// 这里逐字节累乘 128 权重,把编码值还原成真实长度。pCurrent := pEncodedBytes;bDone := FALSE;uiCount := 0;WHILE uiCount < 4 DO    IF uiCount = 0 THEN        uiValue := 0;        uiMultiplier := 1;    END_IF    // 低 7 位是本字节贡献的值,最高位是“后面是否还有字节”的续位标志。    byByte := pCurrent^;    uiValue := uiValue + (BYTE_TO_UINT(byByte AND 16#7F) * uiMultiplier);    uiMultiplier := uiMultiplier * 128;    uiCount := uiCount + 1;    IF (byByte AND 16#80) = 0 THEN        bDone := TRUE;        EXIT;    END_IF;    pCurrent := pCurrent + 1;END_WHILE;IF bDone THEN    uiDecodedLength := uiValue;    uiBytesUsed := uiCount;ELSE    // 超过 4 字节仍未结束时视为非法编码,输出清零并报失败。    uiDecodedLength := 0;    uiBytesUsed := 0;END_IF;

完整代码 6:M_EncodeRemainingLength.st

这一段完整公开 M_EncodeRemainingLength.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_EncodeRemainingLength/// 功能      : 编码 MQTT 剩余长度字段/// 说明      : 将剩余长度按 MQTT 可变长度格式写入缓冲区并返回字节数。/// 编程人员  : ControlRookie/// 时间      : 2026-05-05/// 版本      : V1.0/// ======================================================================={attribute 'hide_all_locals'}METHOD M_EncodeRemainingLength : UINTVAR_INPUT    udiLength    : UDINT;             // 待编码写入报文头的 MQTT 剩余长度[byte]    pBuffer      : POINTER TO BYTE;   // 指向剩余长度编码输出起始地址的指针END_VARVAR    uiBytes      : UINT := 0;         // 当前已写入的 VBI 编码字节数[byte]    byEncodedByte: BYTE;              // 当前准备写入缓冲区的 1 个 VBI 编码字节    udiX         : UDINT;             // Remaining Length 编码过程中的剩余待分解数值[byte]    pByte        : POINTER TO BYTE;   // 当前 VBI 编码字节写入位置指针    uiLoopGuard  : UINT := 0;         // VBI 编码循环保护计数器(最多允许写 4 个字节)END_VAR// === IMPLEMENTATION ===// Remaining Length 采用 MQTT 可变字节整数编码:// 每个字节低 7 位承载数值,最高位表示“后面是否还有后续字节”。pByte := pBuffer;udiX := udiLength;REPEAT    byEncodedByte := UDINT_TO_BYTE(udiX MOD 128);    udiX := udiX / 128;    // 只要后面还有剩余数值,就把续位标志位置 1。    IF udiX > 0 THEN        byEncodedByte := byEncodedByte OR 16#80;    END_IF    pByte^ := byEncodedByte;    pByte := pByte + 1;    uiBytes := uiBytes + 1;    // MQTT 标准规定 Remaining Length 最多只允许编码成 4 个字节,这里用保护计数强制收口。    uiLoopGuard := uiLoopGuard + 1;UNTIL(udiX = 0 OR uiLoopGuard >= 4)END_REPEATM_EncodeRemainingLength := uiBytes;

完整代码 7:M_DecodeRemainingLength.st

这一段完整公开 M_DecodeRemainingLength.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_DecodeRemainingLength/// 功能      : 解码 MQTT 剩余长度字段/// 说明      : 从缓冲区解析可变长度编码,返回消耗字节数并输出长度值。/// 编程人员  : ControlRookie/// 时间      : 2026-05-05/// 版本      : V1.0/// ======================================================================={attribute 'hide_all_locals'}METHOD M_DecodeRemainingLength : UINTVAR_INPUT    pBuffer     : POINTER TO BYTE; // 指向 MQTT 剩余长度编码起始字节的指针END_VARVAR_OUTPUT    uiLength            : UINT;          // 解码得到的 MQTT 剩余长度[byte]END_VARVAR    uiBytes             : UINT := 0;     // 当前已消费的编码字节数[byte]    uiMultiplier        : UINT := 1;     // 可变字节整数权重    byEncodedByte       : BYTE;          // 当前编码字节    pByte               : POINTER TO BYTE;// 当前读取指针END_VAR// === IMPLEMENTATION ===pByte := pBuffer;uiLength := 0;REPEAT    byEncodedByte := pByte^;    uiLength := uiLength + ((byEncodedByte AND 127) * uiMultiplier);    uiMultiplier := uiMultiplier * 128;    pByte := pByte + 1;    uiBytes := uiBytes + 1;UNTIL (byEncodedByte AND 128) = 0 OR uiBytes >= 4END_REPEATM_DecodeRemainingLength := uiBytes;

完整代码 8:M_AppendString.st

这一段完整公开 M_AppendString.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_AppendString/// 功能      : 追加 UTF-8 字符串到发送缓冲区/// 说明      : 先写入 2 字节长度前缀,再写入字符串内容并返回总字节数。/// 编程人员  : ControlRookie/// 时间      : 2026-05-05/// 版本      : V1.0/// ======================================================================={attribute 'hide_all_locals'}METHOD M_AppendString : UINTVAR_INPUT    sStr        : STRING(GVL_Mqtt.cnMaxPayloadSize); // 需要按 MQTT UTF-8 字符串格式写入的文本内容    pBuffer     : POINTER TO BYTE;   // 指向目标字符串写入起始地址的缓冲区指针END_VARVAR    uiLen       : UINT;              // 待写入字符串内容长度[byte]    i           : DINT;              // 逐字节复制字符串内容时使用的循环索引    pWrite      : POINTER TO BYTE;   // 当前字符串写入位置指针END_VAR// === IMPLEMENTATION ===uiLen := TO_UINT(LEN(sStr));// 长度前缀(MSB + LSB)pWrite := pBuffer;pWrite^ := UINT_TO_BYTE(SHR(uiLen, 8));pWrite := pWrite + 1;pWrite^ := UINT_TO_BYTE(uiLen AND 16#FF);// 字符串内容pWrite := pBuffer + 2;IF uiLen > 0 THEN    FOR i := 1 TO TO_DINT(uiLen) DO        pWrite^ := TO_BYTE(sStr[i - 1]);        pWrite := pWrite + 1;    END_FOREND_IFM_AppendString := uiLen + 2;

完整代码 9:M_AppendPayload.st

这一段完整公开 M_AppendPayload.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_AppendPayload/// 功能      : 追加消息载荷到发送缓冲区/// 说明      : 按字节拷贝字符串载荷并返回写入字节数。/// 编程人员  : ControlRookie/// 时间      : 2026-05-05/// 版本      : V1.0/// ======================================================================={attribute 'hide_all_locals'}METHOD M_AppendPayload : UINTVAR_INPUT    sPayload    : STRING(GVL_Mqtt.cnMaxPayloadSize); // 需要原样拷贝到 MQTT 载荷区的字符串内容    pBuffer     : POINTER TO BYTE;   // 指向目标载荷写入起始地址的缓冲区指针END_VARVAR    uiLen       : UINT;              // 待写入字符串载荷长度[byte]    i           : DINT;              // 逐字节复制载荷时使用的循环索引    pWrite      : POINTER TO BYTE;   // 当前载荷写入位置指针END_VAR// === IMPLEMENTATION ===uiLen := TO_UINT(LEN(sPayload));pWrite := pBuffer;IF uiLen > 0 THEN    FOR i := 1 TO TO_DINT(uiLen) DO        pWrite^ := TO_BYTE(sPayload[i - 1]);        pWrite := pWrite + 1;    END_FOREND_IFM_AppendPayload := uiLen;

完整代码 10:M_CopyBytesToString.st

这一段完整公开 M_CopyBytesToString.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_CopyBytesToString/// 功能      : 将字节缓冲区复制到字符串/// 说明      : 用顺序拷贝替代逐字符 CONCAT,降低接收解析中的字符串构造开销。/// 编程人员  : ControlRookie/// 时间      : 2026-05-07/// 版本      : V2.0/// ======================================================================={attribute 'hide_all_locals'}METHOD M_CopyBytesToString : BOOLVAR_INPUT    pSource       : POINTER TO BYTE;   // 源字节缓冲区首地址    uiByteCount   : UINT;              // 计划从源缓冲区复制到字符串的字节数[byte]END_VARVAR_IN_OUT    sTarget       : STRING;            // 目标字符串END_VARVAR    pRead         : POINTER TO BYTE;   // 当前源读取指针    pWrite        : POINTER TO BYTE;   // 当前目标写入指针    uiCopyLen     : UINT;              // 实际复制字节数    uiTargetLen   : UINT;              // 目标字符串最大可写字符数    i             : DINT;              // 循环索引END_VAR// === IMPLEMENTATION ===pWrite := ADR(sTarget);// 零长度时按“合法空字符串”处理,显式写入终止符。IF uiByteCount = 0 THEN    pWrite^ := 0;    M_CopyBytesToString := TRUE;    RETURN;END_IF// 空指针代表上游解析上下文异常,返回 FALSE 并输出空字符串。IF pSource = 0 THEN    pWrite^ := 0;    M_CopyBytesToString := FALSE;    RETURN;END_IF// 目标缓冲区至少要能放下 1 个字符串结束符。IF SIZEOF(sTarget) <= 1 THEN    pWrite^ := 0;    M_CopyBytesToString := FALSE;    RETURN;END_IF// 实际复制长度永远裁剪到目标字符串可容纳的最大字符数,避免越界写入。uiTargetLen := TO_UINT(SIZEOF(sTarget) - 1);uiCopyLen := uiByteCount;IF uiCopyLen > uiTargetLen THEN    uiCopyLen := uiTargetLen;END_IFpRead := pSource;IF uiCopyLen > 0 THEN    // 逐字节顺序拷贝比反复 CONCAT 更轻量,适合接收路径里的高频字符串组装。    FOR i := 1 TO TO_DINT(uiCopyLen) DO        pWrite^ := pRead^;        pWrite := pWrite + 1;        pRead := pRead + 1;    END_FOREND_IF// 手动补 0 结束符,把原始字节缓冲区显式收口成 IEC STRING。pWrite^ := 0;M_CopyBytesToString := TRUE;

完整代码 11:M_ReadIntoBuffer.st

这一段完整公开 M_ReadIntoBuffer.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_ReadIntoBuffer/// 功能      : 统一执行接收并累加到缓冲区/// 说明      : 读取 TCP 数据并做边界检查,成功返回 TRUE/// 编程人员  : ControlRookie/// 时间      : 2026-05-08/// 版本      : V2.0/// ======================================================================={attribute 'hide_all_locals'}METHOD M_ReadIntoBuffer : BOOLVAREND_VAR// === IMPLEMENTATION ===// 先打开底层读取请求;真正是否拿到数据,由 M_TcpRead 回填的 bHasRead 决定。bTcpRead := TRUE;// 本周期底层还没拿到数据时,先退出,等待下一个扫描周期继续。IF NOT bHasRead THEN    M_ReadIntoBuffer := FALSE;    RETURN;END_IFbTcpRead := FALSE;// 把本次读取结果拼到接收缓冲区尾部前,先做容量保护。IF uiRxLength + TO_UINT(udiBytesRead) > SIZEOF(aRxBuf) THEN    M_SetError(        uiErrorCode := TO_UINT(E_ReasonCode.uiErrBufferOverflow),        sMessage := 'Receive buffer overflow');    eState := E_MqttState.iTcpDisconnect;    M_ReadIntoBuffer := FALSE;    RETURN;END_IFuiRxLength := uiRxLength + TO_UINT(udiBytesRead);M_ReadIntoBuffer := TRUE;

完整代码 12:M_IsValidUtf8String.st

这一段完整公开 M_IsValidUtf8String.st。读代码时先看对象职责,再看状态、长度、错误和返回值,不要只抄几行赋值。

/// =======================================================================/// 名称      : M_IsValidUtf8String/// 功能      : 校验字符串是否满足 MQTT UTF-8 基础约束/// 说明      : 当前实现做 PLC 可承受范围内的基础校验,拒绝 NUL、代理区与非法续字节/// 编程人员  : ControlRookie/// 时间      : 2026-05-05/// 版本      : V1.0/// ======================================================================={attribute 'hide_all_locals'}METHOD M_IsValidUtf8String : BOOLVAR_INPUT    sValue               : STRING(GVL_Mqtt.cnMaxTopicLen); // 待校验字符串END_VARVAR    uiLen                : UINT;           // 字符串长度    uiIndex              : UINT;           // 当前扫描到待校验字符串的第几个字节位置    byLead               : BYTE;           // 首字节    byCont1              : BYTE;           // 第 1 个续字节    byCont2              : BYTE;           // 第 2 个续字节    byCont3              : BYTE;           // 第 3 个续字节END_VAR// === IMPLEMENTATION ===/// MQTT 字符串在协议层要求使用 UTF-8。/// 这里按字节扫描,拒绝最常见的非法场景:/// - NUL 字节/// - 残缺多字节序列/// - 非法续字节/// - 代理区和超出 Unicode 上限的编码uiLen := TO_UINT(LEN(sValue));uiIndex := 1;WHILE uiIndex <= uiLen DO    byLead := TO_BYTE(sValue[uiIndex - 1]);    /// MQTT UTF-8 字符串中不允许出现 NUL。    IF byLead = 0 THEN        M_IsValidUtf8String := FALSE;        RETURN;    END_IF    IF byLead < 16#80 THEN        /// 单字节 ASCII。        uiIndex := uiIndex + 1;    ELSIF (byLead >= 16#C2) AND (byLead <= 16#DF) THEN        /// 2 字节序列:110xxxxx 10xxxxxx        IF uiIndex + 1 > uiLen THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        byCont1 := TO_BYTE(sValue[uiIndex]);        IF (byCont1 < 16#80) OR (byCont1 > 16#BF) THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        uiIndex := uiIndex + 2;    ELSIF byLead = 16#E0 THEN        /// 3 字节序列特例:限制第二字节下界,避免过短编码。        IF uiIndex + 2 > uiLen THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        byCont1 := TO_BYTE(sValue[uiIndex]);        byCont2 := TO_BYTE(sValue[uiIndex + 1]);        IF (byCont1 < 16#A0) OR (byCont1 > 16#BF) OR           (byCont2 < 16#80) OR (byCont2 > 16#BF) THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        uiIndex := uiIndex + 3;    ELSIF ((byLead >= 16#E1) AND (byLead <= 16#EC)) OR ((byLead >= 16#EE) AND (byLead <= 16#EF)) THEN        /// 常规 3 字节序列。        IF uiIndex + 2 > uiLen THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        byCont1 := TO_BYTE(sValue[uiIndex]);        byCont2 := TO_BYTE(sValue[uiIndex + 1]);        IF (byCont1 < 16#80) OR (byCont1 > 16#BF) OR           (byCont2 < 16#80) OR (byCont2 > 16#BF) THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        uiIndex := uiIndex + 3;    ELSIF byLead = 16#ED THEN        /// 代理区特例:第二字节只能到 16#9F,避免落入 UTF-16 surrogate 范围。        IF uiIndex + 2 > uiLen THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        byCont1 := TO_BYTE(sValue[uiIndex]);        byCont2 := TO_BYTE(sValue[uiIndex + 1]);        IF (byCont1 < 16#80) OR (byCont1 > 16#9F) OR           (byCont2 < 16#80) OR (byCont2 > 16#BF) THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        uiIndex := uiIndex + 3;    ELSIF byLead = 16#F0 THEN        /// 4 字节序列下界特例:避免过短编码。        IF uiIndex + 3 > uiLen THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        byCont1 := TO_BYTE(sValue[uiIndex]);        byCont2 := TO_BYTE(sValue[uiIndex + 1]);        byCont3 := TO_BYTE(sValue[uiIndex + 2]);        IF (byCont1 < 16#90) OR (byCont1 > 16#BF) OR           (byCont2 < 16#80) OR (byCont2 > 16#BF) OR           (byCont3 < 16#80) OR (byCont3 > 16#BF) THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        uiIndex := uiIndex + 4;    ELSIF (byLead >= 16#F1) AND (byLead <= 16#F3) THEN        /// 常规 4 字节序列。        IF uiIndex + 3 > uiLen THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        byCont1 := TO_BYTE(sValue[uiIndex]);        byCont2 := TO_BYTE(sValue[uiIndex + 1]);        byCont3 := TO_BYTE(sValue[uiIndex + 2]);        IF (byCont1 < 16#80) OR (byCont1 > 16#BF) OR           (byCont2 < 16#80) OR (byCont2 > 16#BF) OR           (byCont3 < 16#80) OR (byCont3 > 16#BF) THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        uiIndex := uiIndex + 4;    ELSIF byLead = 16#F4 THEN        /// 4 字节序列上界特例:Unicode 最高只允许到 U+10FFFF。        IF uiIndex + 3 > uiLen THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        byCont1 := TO_BYTE(sValue[uiIndex]);        byCont2 := TO_BYTE(sValue[uiIndex + 1]);        byCont3 := TO_BYTE(sValue[uiIndex + 2]);        IF (byCont1 < 16#80) OR (byCont1 > 16#8F) OR           (byCont2 < 16#80) OR (byCont2 > 16#BF) OR           (byCont3 < 16#80) OR (byCont3 > 16#BF) THEN            M_IsValidUtf8String := FALSE;            RETURN;        END_IF        uiIndex := uiIndex + 4;    ELSE        /// 其余首字节模式都不属于 MQTT 可接受的 UTF-8 编码。        M_IsValidUtf8String := FALSE;        RETURN;    END_IFEND_WHILEM_IsValidUtf8String := TRUE;

这一篇你最该记住的几句话

  1. 源码加更不是片段展示,而是完整源码对象公开讲解。
  2. 先建立对象地图,再读状态、报文和事务,现场调试才不会迷路。
  3. 判断源码成熟度,不只看功能是否实现,还要看边界、错误和在线观测量是否闭环。

系列导航

  • 系列定位:MqttClient 系列教程,源码加更阶段,第 13 篇 / 共 16 篇
  • 上一篇:源码加更02
  • 下一篇:源码加更04
基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-06-21 12:22:40 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/777376.html
  2. 运行时间 : 0.136397s [ 吞吐率:7.33req/s ] 内存消耗:4,820.22kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=a57485af1450af19b505ea29f2efad11
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000475s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000767s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000311s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000347s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000783s ]
  6. SELECT * FROM `set` [ RunTime:0.009724s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000694s ]
  8. SELECT * FROM `article` WHERE `id` = 777376 LIMIT 1 [ RunTime:0.001429s ]
  9. UPDATE `article` SET `lasttime` = 1782015760 WHERE `id` = 777376 [ RunTime:0.004266s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000316s ]
  11. SELECT * FROM `article` WHERE `id` < 777376 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000459s ]
  12. SELECT * FROM `article` WHERE `id` > 777376 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000510s ]
  13. SELECT * FROM `article` WHERE `id` < 777376 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001082s ]
  14. SELECT * FROM `article` WHERE `id` < 777376 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001484s ]
  15. SELECT * FROM `article` WHERE `id` < 777376 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.002884s ]
0.138107s