很多人需要编写基于MFC的上位机程序,而这类程序首先要解决的就是网络通信的问题,这里也抽出一点时间写了一个简单的额范例,如果你的需求是如下几幅图片所示(这里用TCP调试助手模拟下位机,以便更清楚的看到我们发的信息),那么不妨可以下载下来看一看,程序的代码已经给了非常详细的注释,这里不再赘述,只放一些核心代码:
这里附上程序的下载地址,自己手工 码的程序,收一点点豆子,核心代码我也直接附出来:程序下载地址
TCP调试助手程序下载地址(必须要设置下载豆,这个软件大家也可以网上下载,豆多的掠过):TCP/UDP调试助手下载地址
先说一下程序的运行平台,以免各位下载程序跑的时候出现莫名的报错,本程序已经经过VS2013编译通过及运行:
同时要设置本机的IP地址,比如我的这里设置的是:192.168.0.105,具体设置方法请百度:
TCP模拟调试助手时,我们选择创建服务器,具体创建过程见图:
创建成功后启动:
//设备连接按钮的代码
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);
}