很多人需要编写基于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);
}