这段代码实现了一个远程客户端对话框的功能,主要涉及网络通信和树形目录显示。下面我将详细分析其编码逻辑:
1. SendCommandPacket 方法
这是核心的网络通信方法,负责发送命令包并处理响应:
int CRomoteClientDlg::SendCommandPacket(int nCmd, bool bAutoClose, BYTE* pData, size_t nLength)
{
UpdateData(); // 更新对话框数据
// 获取客户端Socket单例并初始化
CClientSocket* pClient = CClientSocket::getInstance();
bool ret = pClient->InitSocket(m_server_address, atoi((LPCTSTR)m_nPort));
if (!ret) {
AfxMessageBox("网络初始化失败!");
return -1;
}
// 创建并发送命令包
CPacket pack(nCmd, pData, nLength);
ret = pClient->Send(pack);
TRACE("send ret %d \r\n", ret);
// 处理服务器响应
int cmd = pClient->DealCommand();
TRACE("ack:%d\r\n", cmd);
// 根据参数决定是否自动关闭socket
if (bAutoClose)
pClient->CloseSocket();
return cmd;
}
-
更新对话框数据
-
获取CClientSocket单例并初始化socket连接
-
创建命令包(包含命令号、数据和长度)
-
发送命令包到服务器
-
接收并处理服务器响应
-
根据bAutoClose参数决定是否关闭连接
-
返回服务器响应的命令号
2. OnBnClickedBtnFileinfo 方法
处理"文件信息"按钮点击事件,获取驱动器列表并显示在树形控件中:
void CRomoteClientDlg::OnBnClickedBtnFileinfo()
{
// 发送命令1(获取驱动器列表)
int ret = SendCommandPacket(1);
if (ret == -1) {
AfxMessageBox(_T("命令处理失败!!!"));
return;
}
// 获取返回的驱动器列表数据
CClientSocket* pClient = CClientSocket::getInstance();
std::string drivers = pClient->GetPacket().strData;
std::string dr;
// 清空树形控件并逐个添加驱动器
m_Tree.DeleteAllItems();
for (size_t i = 0; i < drivers.size(); i++)
{
if (drivers[i] == ',') {
dr += ":";
m_Tree.InsertItem(dr.c_str(),TVI_ROOT,TVI_LAST);
dr.clear();
continue;
}
dr += drivers[i];
}
}
逻辑流程:
-
发送命令1到服务器获取驱动器列表
-
检查返回结果是否成功
-
从socket包中获取驱动器字符串(格式如"C,D,E")
-
清空树形控件
-
解析驱动器字符串,逐个添加到树形控件的根节点下
3. GetPath 方法
根据树形控件中的选中项构建完整路径:
CString CRomoteClientDlg::GetPath(HTREEITEM hTree)
{
CString strRet, strTmp;
do {
strTmp = m_Tree.GetItemText(hTree); // 获取当前节点文本
strRet = strTmp + '\\' + strRet; // 拼接路径
hTree = m_Tree.GetParentItem(hTree); // 获取父节点
} while (hTree != NULL); // 直到根节点
return strRet;
}
逻辑流程:
-
从指定树节点开始
-
循环获取当前节点文本和父节点
-
反向拼接路径字符串(从子节点到根节点)
-
返回完整路径字符串
4. OnNMDblclkTreeDir 方法
处理树形控件双击事件,获取选中目录的文件信息:
void CRomoteClientDlg::OnNMDblclkTreeDir(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
// 获取鼠标位置和选中的树节点
CPoint ptMouse;
GetCursorPos(&ptMouse);
m_Tree.ScreenToClient(&ptMouse);
HTREEITEM hTreeSelected = m_Tree.HitTest(ptMouse,0);
if (hTreeSelected == NULL)
return;
// 获取选中节点的完整路径
CString strPath = GetPath(hTreeSelected);
// 发送命令2(获取目录文件信息)
SendCommandPacket(2, FALSE, (BYTE*)(LPCTSTR)strPath, strPath.GetLength());
// 处理返回的文件信息
PFILEINFO pInfo = (PFILEINFO)CClientSocket::getInstance()->GetPacket().Data();
CClientSocket* pClient = CClientSocket::getInstance();
// 如果文件信息有后续数据,继续接收
if (pInfo->HasNext) {
int cmd = pClient->DealCommand();
TRACE("ack:%d\r\n", cmd);
//TODO:处理收到的数据
}
pClient->CloseSocket();
}
逻辑流程:
-
获取鼠标位置并转换为树形控件坐标
-
检测双击的树节点
-
获取选中节点的完整路径
-
发送命令2(带路径参数)到服务器获取文件信息
-
接收并处理文件信息
-
检查是否有后续数据需要接收
-
关闭socket连接
整体设计特点
-
网络通信封装:使用SendCommandPacket方法封装了常用的网络操作,简化了其他方法的调用
-
单例模式:CClientSocket使用单例模式确保全局只有一个socket连接
-
树形控件交互:实现了路径获取和双击事件处理
-
命令驱动:使用不同的命令号(1,2等)区分不同的操作
-
错误处理:基本的错误检查和用户提示
494

被折叠的 条评论
为什么被折叠?



