a
This commit is contained in:
@@ -0,0 +1,326 @@
|
||||
# 网络通信
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [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)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
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 子目录。
|
||||
|
||||
```mermaid
|
||||
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.h](file://h/TcpClient.h#L1-L76)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L1-L449)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h#L1-L50)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L1-L200)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
|
||||
- [Constant.h](file://h/Constant.h#L220-L235)
|
||||
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L470-L504)
|
||||
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1-L120)
|
||||
|
||||
章节来源
|
||||
- [TcpClient.h](file://h/TcpClient.h#L1-L76)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L1-L120)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h#L1-L50)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L1-L120)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
|
||||
- [Constant.h](file://h/Constant.h#L220-L235)
|
||||
|
||||
## 核心组件
|
||||
- TcpClient:封装 TCP 套接字生命周期、连接管理、数据收发、连接状态检测与重连。
|
||||
- CTransferCtrl:基于 TcpClient 的控制协议封装,负责控制命令的打包、发送与响应解析,以及与业务层交互。
|
||||
|
||||
章节来源
|
||||
- [TcpClient.h](file://h/TcpClient.h#L18-L76)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L26-L120)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h#L34-L50)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L120-L180)
|
||||
|
||||
## 架构总览
|
||||
下图展示 TcpClient 与 CTransferCtrl 的类关系、关键成员与方法,以及与协议定义的关联。
|
||||
|
||||
```mermaid
|
||||
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 : "继承"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [TcpClient.h](file://h/TcpClient.h#L18-L76)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h#L34-L50)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 套接字创建与流式配置
|
||||
- socket 创建:构造函数初始化成员,InitailTcp 在首次使用前创建流式套接字(AF_INET, SOCK_STREAM)。
|
||||
- 缓冲区设置:通过 SO_RCVBUF/SO_SNDBUF 设置收发缓冲区大小。
|
||||
- 连接保活:启用 SO_KEEPALIVE,提升链路异常检测能力。
|
||||
- 关闭策略:禁用 SO_LINGER(立即丢弃未发送数据),避免长时间等待导致阻塞。
|
||||
|
||||
章节来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L48-L99)
|
||||
|
||||
### connect 建立连接与三次握手
|
||||
- 连接发起:ConnectServer 将目标地址转换为 sockaddr_in 并调用 connect。
|
||||
- 三次握手:由系统内核完成,应用层无需显式处理握手细节。
|
||||
- 超时策略:当前实现未对 connect 设置超时,如需超时可在上层封装 select 或非阻塞 + 超时判断(建议在业务层统一处理)。
|
||||
|
||||
章节来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L101-L130)
|
||||
|
||||
### SendData 发送逻辑
|
||||
- 连接状态检查:发送前调用 GetConnectStatus,若连接中断则返回错误。
|
||||
- send 调用:调用 send 发送数据,记录日志与错误码。
|
||||
- 返回值语义:返回实际发送字节数或错误标识,便于上层判断。
|
||||
|
||||
章节来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L149-L177)
|
||||
|
||||
### RecvData 接收逻辑与非阻塞 select
|
||||
- 非阻塞探测:使用 select 设置超时(微秒级),在无数据时快速返回。
|
||||
- 可读判定:select 返回正值且 FD_ISSET 检测到可读时,执行 recv。
|
||||
- 异常处理:recv 返回非正数时标记连接中断并更新状态。
|
||||
|
||||
章节来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L282-L354)
|
||||
|
||||
### GetConnectStatus 连接存活检测
|
||||
- select 立即轮询:使用零超时的 select 检查可读事件。
|
||||
- MSG_PEEK 探测:对可读套接字执行 MSG_PEEK 探测,若返回值小于等于 0,通常表示对端关闭或连接异常。
|
||||
- 状态维护:根据探测结果更新 m_bIsConnect。
|
||||
|
||||
章节来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L201-L249)
|
||||
|
||||
### ReConnect 重连机制
|
||||
- 资源释放:先调用 CloseConnect 关闭当前连接。
|
||||
- 新建套接字:调用 InitailTcp 重新创建套接字,以规避某些平台/驱动下“仅关闭连接无法再次成功”的限制。
|
||||
- 再连接:使用原 IP/端口重新 ConnectToServer。
|
||||
|
||||
章节来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L252-L278)
|
||||
|
||||
### CTransferCtrl 控制协议封装
|
||||
- 初始化:Initialize 调用基类 InitailTcp 完成套接字准备。
|
||||
- 发送控制:SendCtrlInfoToDev 构造协议头与数据,调用 SendData 发送。
|
||||
- 接收控制:RecvCtrlMsg/RecvRspMsg/RecvCommRspMsg 实现头部解析、长度校验、CRC 校验与超时处理。
|
||||
- 协议常量:使用 CtrlProtocolDef.h 中的命令字、结构体与枚举。
|
||||
|
||||
章节来源
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L72-L180)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L245-L400)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L441-L548)
|
||||
|
||||
### 设备固件升级与数据同步场景
|
||||
- 固件升级:checkupdate.cpp 展示了通过网络下载升级文件、向设备发送文件与执行升级命令的流程,体现网络通信在升级中的作用。
|
||||
- 数据同步:devmngframe.cpp 展示了设备参数同步、任务参数下发与云端托管任务的交互,CTransferCtrl 在其中承担控制通道。
|
||||
|
||||
章节来源
|
||||
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1-L120)
|
||||
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1042-L1336)
|
||||
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L470-L504)
|
||||
|
||||
## 依赖关系分析
|
||||
- CTransferCtrl 依赖 TcpClient 提供的套接字生命周期与收发能力。
|
||||
- CTransferCtrl 依赖 CtrlProtocolDef.h 的协议结构与命令字。
|
||||
- TcpClient 依赖 Constant.h 中的缓冲区大小与超时常量。
|
||||
- 视图层与操作层通过 CTransferCtrl 间接使用网络通信。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
TCtrl["CTransferCtrl"] --> TC["CTcpClient"]
|
||||
TCtrl --> Proto["CtrlProtocolDef.h"]
|
||||
TC --> Const["Constant.h"]
|
||||
View["devmngframe.cpp"] --> TCtrl
|
||||
Upg["checkupdate.cpp"] --> TCtrl
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L1-L120)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L1-L120)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
|
||||
- [Constant.h](file://h/Constant.h#L220-L235)
|
||||
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L470-L504)
|
||||
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1-L120)
|
||||
|
||||
## 性能考量
|
||||
- 缓冲区大小:通过 SO_RCVBUF/SO_SNDBUF 调整可减少系统调用次数,提高吞吐。
|
||||
- 非阻塞接收:使用 select 微秒级超时,避免长时间阻塞,适合高频轮询场景。
|
||||
- MSG_PEEK 探测:零拷贝探测连接状态,降低开销。
|
||||
- 重连策略:在出现异常时主动重建套接字,避免复用旧句柄导致的不可达。
|
||||
|
||||
[本节为通用指导,无需列出具体文件来源]
|
||||
|
||||
## 故障排查指南
|
||||
- 连接失败:检查 InitailTcp 是否成功创建套接字、SOCK_STREAM 参数是否正确、SO_LINGER 与 SO_KEEPALIVE 设置是否生效。
|
||||
- 发送失败:关注 WSAGetLastError 返回值,结合日志定位错误码。
|
||||
- 接收超时:确认 RecvData 的 select 超时设置是否合理,避免过短导致频繁超时。
|
||||
- 连接中断:GetConnectStatus 的 MSG_PEEK 探测返回非正数时,应视为连接异常并触发重连。
|
||||
- 重连无效:若仅关闭连接而不重建套接字,可能无法再次连接,需遵循 ReConnect 的重建策略。
|
||||
|
||||
章节来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L48-L99)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L149-L177)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L282-L354)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L201-L249)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L252-L278)
|
||||
|
||||
## 结论
|
||||
TcpClient 提供了简洁可靠的 TCP 客户端基础能力:套接字创建与配置、连接管理、非阻塞数据收发、连接状态探测与重连。CTransferCtrl 在此基础上实现了控制协议的编解码与业务交互,支撑设备固件升级与数据同步等场景。通过 MSG_PEEK 与 select 的组合,能够高效检测连接状态并在异常时快速恢复。建议在业务层补充 connect 超时与更细粒度的错误分类,以进一步提升鲁棒性。
|
||||
|
||||
[本节为总结性内容,无需列出具体文件来源]
|
||||
|
||||
## 附录
|
||||
|
||||
### 关键流程图
|
||||
|
||||
#### 连接建立与状态检测序列
|
||||
```mermaid
|
||||
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 : "返回连接状态"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L48-L130)
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L201-L249)
|
||||
|
||||
#### 数据发送与接收流程
|
||||
```mermaid
|
||||
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(["返回成功"])
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L282-L354)
|
||||
|
||||
#### 重连机制流程
|
||||
```mermaid
|
||||
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
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L252-L278)
|
||||
|
||||
### 应用示例路径
|
||||
- 设备参数同步与云端托管任务交互:参见 [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L470-L504)
|
||||
- 固件升级流程(下载、发送文件、执行升级命令):参见 [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1042-L1336)
|
||||
- 控制协议发送与接收:参见 [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L120-L180)、[TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L245-L400)
|
||||
Reference in New Issue
Block a user