Files
T
coco df489d5640 a
2026-07-03 16:05:30 +08:00

14 KiB
Raw Blame History

网络通信

**本文引用的文件** - [TcpClient.h](file://h/TcpClient.h) - [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp) - [TransferCtrl.h](file://h/TransferCtrl.h) - [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp) - [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h) - [Constant.h](file://h/Constant.h) - [devmngframe.cpp](file://cpp/Views/devmngframe.cpp) - [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件围绕 TcpClient 类实现的 TCP 客户端通信机制进行深入解析,覆盖 socket 创建、SOCK_STREAM 流式套接字配置、SO_LINGER 和 SO_KEEPALIVE 等套接字选项的作用与效果;connect 建立连接的三次握手过程与超时策略;SendData/RecvData 中 send/recv 的调用逻辑、非阻塞模式下的 select 使用、MSG_PEEK 探测接收状态与错误码处理;ReConnect 重连机制的实现、closesocket 资源释放与新 socket 重建的必要性;GetConnectStatus 通过 select+recv(MSG_PEEK) 组合检测连接存活状态的技术细节。最后给出连接管理、数据收发、异常重连与资源清理的完整流程图与示例路径,并说明在设备固件升级与数据同步场景中的应用。

项目结构

该项目为桌面应用工程,网络通信相关代码集中在 Tools 子目录,核心类为 TcpClient 与派生类 CTransferCtrl;协议定义位于 CtrlProtocolDef.h;常量与全局配置位于 Constant.h;设备管理与同步界面位于 Views 子目录;固件升级逻辑位于 Tools 子目录。

graph TB
subgraph "网络工具层"
TC["TcpClient<br/>h/TcpClient.h<br/>cpp/Tools/TcpClient.cpp"]
TCtrl["CTransferCtrl<br/>h/TransferCtrl.h<br/>cpp/Tools/TransferCtrl.cpp"]
end
subgraph "协议与常量"
Proto["CtrlProtocolDef.h"]
Const["Constant.h"]
end
subgraph "业务视图与操作"
View["devmngframe.cpp"]
Upg["checkupdate.cpp"]
end
TCtrl --> TC
TCtrl --> Proto
TC --> Const
View --> TCtrl
Upg --> TCtrl

图表来源

章节来源

核心组件

  • TcpClient:封装 TCP 套接字生命周期、连接管理、数据收发、连接状态检测与重连。
  • CTransferCtrl:基于 TcpClient 的控制协议封装,负责控制命令的打包、发送与响应解析,以及与业务层交互。

章节来源

架构总览

下图展示 TcpClient 与 CTransferCtrl 的类关系、关键成员与方法,以及与协议定义的关联。

classDiagram
class CTcpClient {
+CTcpClient()
+~CTcpClient()
+Initialize() bool
+ConnectToServer(strIP, wPort) bool
+ReConnect() bool
+SendData(pData, iLen) int
+RecvData(pData, iLen, iActualLen) bool
+GetConnectStatus() bool
+CloseConnect() bool
+Disconnect() bool
+ClearRecvBuffer() bool
-InitailTcp() bool
-ConnectServer(strAddr, wPort) bool
-m_strIP : CString
-m_wPort : WORD
-m_iSndBuf : int
-m_iRcvBuf : int
-m_sockClient : SOCKET
-m_bIsConnect : bool
-m_bIsInitialed : bool
-m_pClearRcvBuf : char*
}
class CTransferCtrl {
+Initialize() bool
+SendCtrlInfo(pCtrlHeader, pData, wDataLen, DataType) bool
+RecvCtrlMsg(pData, pLen, iMaxLen, iTimeout) int
+RecvRspMsg(pData, pLen, iMaxLen, iTimeout) int
+GetCtrlRspLength(ucCMd) int
+InitialClient() bool
+IsCtrlMsg(ucCMd) bool
+IsPlcStatusMsg(ucCmd, ucSrcType) bool
+GetPlcAddr() uint32
+GetCurrCtrlCmd() int
-RecvEnoughMsg(pData, iLen, iTimeOut) bool
-RecvCommRspMsg(pData, pLen, iMaxLen, iRcvTimeout, bIsRcvCtrl) int
-SendCtrlInfoToDev(pTransInfo, pData, wDataLen, ucDataType) bool
}
CTransferCtrl --|> CTcpClient : "继承"

图表来源

详细组件分析

套接字创建与流式配置

  • socket 创建:构造函数初始化成员,InitailTcp 在首次使用前创建流式套接字(AF_INET, SOCK_STREAM)。
  • 缓冲区设置:通过 SO_RCVBUF/SO_SNDBUF 设置收发缓冲区大小。
  • 连接保活:启用 SO_KEEPALIVE,提升链路异常检测能力。
  • 关闭策略:禁用 SO_LINGER(立即丢弃未发送数据),避免长时间等待导致阻塞。

章节来源

connect 建立连接与三次握手

  • 连接发起:ConnectServer 将目标地址转换为 sockaddr_in 并调用 connect。
  • 三次握手:由系统内核完成,应用层无需显式处理握手细节。
  • 超时策略:当前实现未对 connect 设置超时,如需超时可在上层封装 select 或非阻塞 + 超时判断(建议在业务层统一处理)。

章节来源

SendData 发送逻辑

  • 连接状态检查:发送前调用 GetConnectStatus,若连接中断则返回错误。
  • send 调用:调用 send 发送数据,记录日志与错误码。
  • 返回值语义:返回实际发送字节数或错误标识,便于上层判断。

章节来源

RecvData 接收逻辑与非阻塞 select

  • 非阻塞探测:使用 select 设置超时(微秒级),在无数据时快速返回。
  • 可读判定:select 返回正值且 FD_ISSET 检测到可读时,执行 recv。
  • 异常处理:recv 返回非正数时标记连接中断并更新状态。

章节来源

GetConnectStatus 连接存活检测

  • select 立即轮询:使用零超时的 select 检查可读事件。
  • MSG_PEEK 探测:对可读套接字执行 MSG_PEEK 探测,若返回值小于等于 0,通常表示对端关闭或连接异常。
  • 状态维护:根据探测结果更新 m_bIsConnect。

章节来源

ReConnect 重连机制

  • 资源释放:先调用 CloseConnect 关闭当前连接。
  • 新建套接字:调用 InitailTcp 重新创建套接字,以规避某些平台/驱动下“仅关闭连接无法再次成功”的限制。
  • 再连接:使用原 IP/端口重新 ConnectToServer。

章节来源

CTransferCtrl 控制协议封装

  • 初始化:Initialize 调用基类 InitailTcp 完成套接字准备。
  • 发送控制:SendCtrlInfoToDev 构造协议头与数据,调用 SendData 发送。
  • 接收控制:RecvCtrlMsg/RecvRspMsg/RecvCommRspMsg 实现头部解析、长度校验、CRC 校验与超时处理。
  • 协议常量:使用 CtrlProtocolDef.h 中的命令字、结构体与枚举。

章节来源

设备固件升级与数据同步场景

  • 固件升级:checkupdate.cpp 展示了通过网络下载升级文件、向设备发送文件与执行升级命令的流程,体现网络通信在升级中的作用。
  • 数据同步:devmngframe.cpp 展示了设备参数同步、任务参数下发与云端托管任务的交互,CTransferCtrl 在其中承担控制通道。

章节来源

依赖关系分析

  • CTransferCtrl 依赖 TcpClient 提供的套接字生命周期与收发能力。
  • CTransferCtrl 依赖 CtrlProtocolDef.h 的协议结构与命令字。
  • TcpClient 依赖 Constant.h 中的缓冲区大小与超时常量。
  • 视图层与操作层通过 CTransferCtrl 间接使用网络通信。
graph LR
TCtrl["CTransferCtrl"] --> TC["CTcpClient"]
TCtrl --> Proto["CtrlProtocolDef.h"]
TC --> Const["Constant.h"]
View["devmngframe.cpp"] --> TCtrl
Upg["checkupdate.cpp"] --> TCtrl

图表来源

性能考量

  • 缓冲区大小:通过 SO_RCVBUF/SO_SNDBUF 调整可减少系统调用次数,提高吞吐。
  • 非阻塞接收:使用 select 微秒级超时,避免长时间阻塞,适合高频轮询场景。
  • MSG_PEEK 探测:零拷贝探测连接状态,降低开销。
  • 重连策略:在出现异常时主动重建套接字,避免复用旧句柄导致的不可达。

[本节为通用指导,无需列出具体文件来源]

故障排查指南

  • 连接失败:检查 InitailTcp 是否成功创建套接字、SOCK_STREAM 参数是否正确、SO_LINGER 与 SO_KEEPALIVE 设置是否生效。
  • 发送失败:关注 WSAGetLastError 返回值,结合日志定位错误码。
  • 接收超时:确认 RecvData 的 select 超时设置是否合理,避免过短导致频繁超时。
  • 连接中断:GetConnectStatus 的 MSG_PEEK 探测返回非正数时,应视为连接异常并触发重连。
  • 重连无效:若仅关闭连接而不重建套接字,可能无法再次连接,需遵循 ReConnect 的重建策略。

章节来源

结论

TcpClient 提供了简洁可靠的 TCP 客户端基础能力:套接字创建与配置、连接管理、非阻塞数据收发、连接状态探测与重连。CTransferCtrl 在此基础上实现了控制协议的编解码与业务交互,支撑设备固件升级与数据同步等场景。通过 MSG_PEEK 与 select 的组合,能够高效检测连接状态并在异常时快速恢复。建议在业务层补充 connect 超时与更细粒度的错误分类,以进一步提升鲁棒性。

[本节为总结性内容,无需列出具体文件来源]

附录

关键流程图

连接建立与状态检测序列

sequenceDiagram
participant App as "应用"
participant Client as "CTcpClient"
participant Kernel as "系统内核"
App->>Client : "Initialize()"
Client->>Kernel : "socket(AF_INET, SOCK_STREAM)"
Client-->>App : "返回初始化结果"
App->>Client : "ConnectToServer(IP, Port)"
Client->>Kernel : "connect(目标地址)"
Kernel-->>Client : "三次握手完成/失败"
Client-->>App : "返回连接结果"
App->>Client : "GetConnectStatus()"
Client->>Kernel : "select(零超时)+recv(MSG_PEEK)"
Kernel-->>Client : "返回可读/不可读"
Client-->>App : "返回连接状态"

图表来源

数据发送与接收流程

flowchart TD
Start(["进入 RecvData"]) --> CheckConn["检查连接状态"]
CheckConn --> ConnOK{"连接正常?"}
ConnOK --> |否| RetFalse["返回失败"]
ConnOK --> |是| SelectWait["select 设置微秒级超时"]
SelectWait --> SelRet{"select 返回值"}
SelRet --> |错误| HandleErr["记录错误并返回失败"]
SelRet --> |超时(0)| RetZero["返回成功(0字节)"]
SelRet --> |可读(>0)| FDCheck["FD_ISSET 检测套接字"]
FDCheck --> FDOK{"可读信号有效?"}
FDOK --> |否| HandleErr
FDOK --> |是| Recv["recv 接收数据"]
Recv --> RecvRet{"recv 返回值<=0"}
RecvRet --> |是| MarkDown["标记连接中断并返回失败"]
RecvRet --> |否| SaveLen["保存实际接收长度"]
SaveLen --> Log["记录日志"]
Log --> Done(["返回成功"])

图表来源

重连机制流程

flowchart TD
RCStart(["ReConnect 开始"]) --> CloseOld["CloseConnect 关闭旧连接"]
CloseOld --> NewSock["InitailTcp 重新创建套接字"]
NewSock --> NewSockOK{"创建成功?"}
NewSockOK --> |否| ShowErr["提示套接字初始化失败"]
ShowErr --> RCEnd(["结束"])
NewSockOK --> |是| Reconnect["ConnectToServer(IP, Port)"]
Reconnect --> RCResult{"连接成功?"}
RCResult --> |是| RCOK["返回成功"]
RCResult --> |否| RCFail["返回失败"]
RCOK --> RCEnd
RCFail --> RCEnd

图表来源

应用示例路径