很多人需要编写基于MFC的上位机程序,而这类程序首先要解决的就是网络通信的问题,这里也抽出一点时间写了一个简单的额范例,如果你的需求是如下几幅图片所示(这里用TCP调试助手模拟下位机,以便更清楚的看到我们发的信息),那么不妨可以下载下来看一看,程序的代码已经给了非常详细的注释,这里不再赘述,只放一些核心代码:
这里附上程序的下载地址,自己手工 码的程序,收一点点豆子,核心代码我也直接附出来:程序下载地址
TCP调试助手程序下载地址(必须要设置下载豆,这个软件大家也可以网上下载,豆多的掠过):TCP/UDP调试助手下载地址
先说一下程序的运行平台,以免各位下载程序跑的时候出现莫名的报错,本程序已经经过VS2013编译通过及运行:
同时要设置本机的IP地址,比如我的这里设置的是:192.168.0.105,具体设置方法请百度:
TCP模拟调试助手时,我们选择创建服务器,具体创建过程见图:
扫描二维码关注公众号,回复:
890977 查看本文章
创建成功后启动:
//设备连接按钮的代码 void CconnectDlg::OnBnClickedConnect() { // TODO: 在此添加控件通知处理程序代码 //测试能不能ping通 int ping_ok = 1; CString serv_addr, serv_port; SECURITY_ATTRIBUTES sa; HANDLE hRead, hWrite; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; CString filename = "ipconfig.ini"; CStdioFile mFileIP(filename, CFile::modeCreate | CFile::modeWrite); //CString str_ip; GetDlgItem(IDC_IP)->GetWindowText(serv_addr); mFileIP.WriteString(serv_addr); mFileIP.Close(); filename = "portconfig.ini"; CStdioFile mFilePort(filename, CFile::modeCreate | CFile::modeWrite); GetDlgItem(IDC_Port)->GetWindowText(serv_port); mFilePort.WriteString(serv_port); mFilePort.Close(); CString strCmd; strCmd = "cmd /k ping ";//加上"cmd /k"是为了能执行类似dir的命令 strCmd += serv_addr; //创建命名管道 if (!CreatePipe(&hRead, &hWrite, &sa, 0)) { return; } STARTUPINFO si; PROCESS_INFORMATION pi; si.cb = sizeof(STARTUPINFO); GetStartupInfo(&si); si.hStdError = hWrite;//数据输出用的文件句柄 si.hStdOutput = hWrite;//数据输出用的文件句柄 si.wShowWindow = SW_HIDE; si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; OutputDebugString("1"); if (!CreateProcess(NULL, strCmd.GetBuffer(strCmd.GetLength())//执行cmd命令,并在命名中管道中写入cmd命令返回的串 , NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi)) { return; } CloseHandle(hWrite); OutputDebugString("2"); char buffer[4096] = { 0 }; DWORD bytesRead; CString strResult = ""; while (1) { memset(buffer, 0, 4096); if (ReadFile(hRead, buffer, 4096, &bytesRead, NULL) != NULL)//从命名管道中读取数据 { if (buffer[18] == 'T') { ping_ok = 0; int port; SOCKADDR_IN addr; WORD wVersionRequested;//定义socket1.1或者socket2.0 WSADATA wsaData; //定义装载socket版本的变量 int err; //错误变量 wVersionRequested = MAKEWORD(2, 2); //定义连接为socket2.0 err = WSAStartup(wVersionRequested, &wsaData); //装载socket2.0支持 if (0 != err)//判断是否装载成功 { return; } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)//判断版本号,是否和定义的一样 { WSACleanup(); //若出问题,卸载支持,并结束程序返回-1 return; } m_socket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0); if (INVALID_SOCKET == m_socket) { MessageBox("创建套接字失败!"); return; } if (SOCKET_ERROR == WSAAsyncSelect(m_socket, m_hWnd, WM_SOCK, FD_READ)) { MessageBox("注册网络读取事件失败!"); return; } if (serv_port == "" || serv_addr == "") { MessageBox("服务器地址或端口不能为空!!!");//该函数功能是弹出一个显示s你写的这些内容的框 } else { port = atoi(serv_port.GetBuffer(1));//将端口字符串转换为数字 addr.sin_family = AF_INET; addr.sin_addr.S_un.S_addr = inet_addr(serv_addr.GetBuffer(1));//转换服务器ip地址 addr.sin_port = ntohs(port); //设置非阻塞模式 unsigned long ul = 1; int ret = ioctlsocket(m_socket, FIONBIO, (unsigned long*)&ul); if (ret == SOCKET_ERROR) exit(0); if (::connect(m_socket, (SOCKADDR*)&addr, sizeof(SOCKADDR))) { CString Str; } else { } } break; } OutputDebugString(buffer); } else { break; } } CloseHandle(hRead); if (ping_ok) { MessageBox("设备连接出错,请检查连接!"); } else { m_connect.EnableWindow(0); m_cut.EnableWindow(1); GetDlgItem(IDC_STATIC_SHOW)->SetWindowText(_T("设备已连接")); AddToInfRec("设备已连接", IDC_Zhuangtai, TRUE, TRUE); CString connected; connected = "设备已经连接"; send(m_socket, connected, 50, 0); MyDevFounded = TRUE; } }
//发送命令按钮代码 void CconnectDlg::OnBnClickedButtonSend() { // TODO: 在此添加控件通知处理程序代码 CString message, showtext, datatest; GetDlgItem(IDC_EDIT_Send)->GetWindowText(message); //从发送数据的edit框中获取信息,存储到message变量中 if (MyDevFounded == FALSE) //进行设备连接状态的判断,通过设置MyDevFounded,初始值为false,设备连接成功后置true { AddToInfRec("设备未找到", IDC_Zhuangtai, TRUE, TRUE);//设备未成功连接,提示设备未找到 return; } if (message == "") { MessageBox("消息不能为空!"); //对发送数据框进行判断 } else { AddToInfRec("发送数据:", IDC_Zhuangtai,0,0); AddToInfRec(message, IDC_Zhuangtai,1,1); //显示发送的数据到状态框 ::send(m_socket, message.GetBuffer(1), message.GetLength(), 0); //通过sock发送数据 } }
//onsock函数代码 afx_msg LRESULT CconnectDlg::OnSock(WPARAM wParam, LPARAM lParam) { char cs[512] = ""; //定义一个用来存放接收数据的字符串cs if (lParam == FD_READ) //sock收到消息,触发FD_READ { if (SOCKET_ERROR == recv(m_socket, cs, 512, NULL))//使用recv函数来进行判别收到的内容 { MessageBox("接收数据失败!"); //如果触发连接错误,则弹出接收数据失败提示框 return FALSE; } else{ AddToInfRec("接收数据:", IDC_EDIT_REC, 0, 0); AddToInfOut(cs, TRUE, TRUE);//如果没有出现错误,将cs中的数据传递给AddToInfOut来进行处理 } } return 0; }
//数据处理函数代码 void CconnectDlg::AddToInfOut(CString InStr, BOOL AddTime, BOOL NewLine) { CString str, str1; UINT i; CHAR SysTime[10]; GetDlgItemText(IDC_EDIT_REC, str); //从数据接收的Edit框中获取已经接收到的信息 str += InStr; //新收到的信息通过InStr传递到本函数中,声明一个字符串str来存放,此条命令是将新收到的信息叠加到以前的信息中 //需要添加时间信息 if (AddTime == TRUE) { _strtime(SysTime); str1 = SysTime; str1 = " (" + str1 + ")"; str += str1; } //需要换行 if (NewLine == TRUE) { str += "\r\n"; } //设置新的文本 SetDlgItemText(IDC_EDIT_REC, str); //将处理后的信息显示到接收的编辑框中 //滚动条自动滚动到最后一行 i = ((CEdit*)GetDlgItem(IDC_EDIT_REC))->GetLineCount(); ((CEdit*)GetDlgItem(IDC_EDIT_REC))->LineScroll(i, 0); }