1.通过调用 Socket 相关函数实现网络通信;
2. 实现界面系统和后台通信系统的协同配合;
3. 回顾常用控件和 GDI 对象的使用方法;
4. 感受 MFC 下多线程的基本用法。
个人 PC,Windows 操作系统,VS2013开发环境。
一、首先打开VS2013选择创建一个MFC项目,我们先设计客户端,按照对应的界面要求设计好后我们就可以添加对应的功能,我们知道,在客户端我们需要经历这样几个步骤,wsastartup,socket,connect,send。因此我们双击发送连接按钮,在这里我们做的是只到连接的工作,具体我们看代码如下:
void CMFCApplication5Dlg::OnBnClickedButton1()
{
UpdateData(TRUE);
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
s1= "WSAstartup failed!";
AfxMessageBox(s1);
return ;
}
sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sHost)
{
s2= "socket error!";
AfxMessageBox(s2);
WSACleanup();
return ;
}
SOCKADDR_IN addrsServ;
int i = 0;
str.Format(_T("%d"), i);
addrsServ.sin_family = AF_INET;
addrsServ.sin_port = htons(9990);
addrsServ.sin_addr.S_un.S_addr = inet_addr("192.168.191.1");
int sSreveraddlen = sizeof(addrsServ);
UpdateData(false);
retval = connect(sHost, (LPSOCKADDR)&addrsServ, sizeof(addrsServ));
if (SOCKET_ERROR == retval)
{
s3= "connect failed!";
AfxMessageBox(s3);
closesocket(sHost);
WSACleanup();
return ;
}
// TODO: 在此添加控件通知处理程序代码
}
二、接下来我们要实现向服务端发送信息,而这个就需要我们双击发送按钮,当我们点击时,实现我们的内容向服务端的发送,因此我们就需要获取每一个编辑框的内容。
代码如下:
void CMFCApplication5Dlg::OnBnClickedButton2()
{
int bufsize;
CString str;
CString str1;
CString str2;
CString str3;
CString str4;
CString str5;
CString str6;
CString str7;
CString str8;
CString str9;
CString str10;
CString str11;
CString str12;
if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck() == 1)
{
str12 = "R";
}
if (((CButton*)GetDlgItem(IDC_RADIO2))->GetCheck() == 1)
{
str12 = "E";
}
str11 = ";";
GetDlgItemText(IDC_EDIT3, str1);
GetDlgItemText(IDC_EDIT4, str2);
GetDlgItemText(IDC_EDIT5, str3);
GetDlgItemText(IDC_EDIT6, str4);
GetDlgItemText(IDC_EDIT7, str5);
GetDlgItemText(IDC_EDIT8, str6);
GetDlgItemText(IDC_EDIT9, str7);
GetDlgItemText(IDC_EDIT10, str8);
GetDlgItemText(IDC_EDIT11, str9);
GetDlgItemText(IDC_EDIT11, str10);
str = str1 + str11 + str2 + str11 + str3 + str11 + str12 + str11 + str4 + str11 + str5 + str11 + str6 + str11 + str7 + str11 + str8 + str11 + str9 + str11 + str10;
USES_CONVERSION;
char *a = T2A(str.GetBuffer(0));
str.ReleaseBuffer();
sprintf_s(buf, "%s", a);
bufsize = send(sHost, buf, strlen(buf), 0);
if (SOCKET_ERROR == bufsize)
{
s5 = "recv failed!";
AfxMessageBox(s5);
closesocket(sHost);
WSACleanup();
return;
}
// TODO: 在此添加控件通知处理程序代码
}
这样我们就完成了客户端的实现。
一、我们首先也是设计页面,其次按照书上的步骤进行操作,一些必备的函数,
调用 WSAStartup()加载 Socket 库进行初始化;
调用 Socket()函数创建基于 TCP 的流式套接字用于主线程的请求监听;
设置服务器端的本机地址:
你的 sockaddr_in 结构.sin_family = AF_INET;
你的 sockaddr_in 结构.sin_port = htons(你的监听端口,比如 9990);
你的 sockaddr_in 结构.s_addr = htonl(INADDR_ANY);
调用 bind()函数将 Socket 与地址进行绑定;
调用 listen()函数设置套接字为监听工作状态。
代码如下:
void CMFCApplication6Dlg::OnBnClickedButton1()
{
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
s1 = "WSAstartup failed!";
return ;
}
s1 = "WSAstartup successed!";
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sServer)
{
s2 = "socket error!";
WSACleanup();
return ;
}
s2 = "socket success!";
SOCKADDR_IN addrsServ;
int i = 0;
str.Format(_T("%d"), i);
addrsServ.sin_family = AF_INET;
addrsServ.sin_port = htons(9990);
addrsServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
int sSreveraddlen = sizeof(addrsServ);
retval = bind(sServer, (const struct sockaddr *)&addrsServ, sizeof(SOCKADDR_IN));
if (SOCKET_ERROR == retval)
{
s3 = "bind failed!";
closesocket(sServer);
WSACleanup();
return ;
}
s3 = "bind successed!";
retval = listen(sServer, 1);
if (SOCKET_ERROR == retval)
{
s4 = "listen failed!";
closesocket(sServer);
WSACleanup();
return ;
}
s4 = "listen successed!";
editt.SetWindowText(s1+"\r\n"+s2+"\r\n"+s3+"\r\n"+s4 );
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)this, 0, NULL);
if (hThread == NULL)
{
CString ss;
ss="Create Thread Failed!! !";
AfxMessageBox(ss);
closesocket(sServer);
WSACleanup();
return;
}
// TODO: 在此添加控件通知处理程序代码
}
二、这里最重要的是添加一个线程,这样当我们执行accept时我们即使产生阻塞也不会影响我们,因为我们将这个进程放在线程里,这样会提高我们的用户体验。
具体我们看代码:
DWORD WINAPI ClientThread(LPVOID lpParameter)
{
CMFCApplication6Dlg * dlg = (CMFCApplication6Dlg*)lpParameter;
SOCKADDR_IN addrcClient;
int cClientaddlen = sizeof(addrcClient);
sClient = accept(sServer, (struct sockaddr *)&addrcClient, &cClientaddlen);
if (INVALID_SOCKET == sClient)
{
s5 = "accept failed!";
AfxMessageBox(s5);
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return 0;
}
s5 = "accept successed!";
AfxMessageBox(s5);
while (1)
{
memset(buf, 0x00, 100);
int bufsize;
retval = recv(sClient,buf,100,0);
if (SOCKET_ERROR == retval)
{
s5 = "recv failed!";
AfxMessageBox(s5);
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return 0;
}
rec = CString(buf);
SYSTEMTIME tm;
GetLocalTime(&tm);
char sDateTime[30];
sprintf(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond);
CString year(sDateTime);
dlg->editstr = dlg->editstr + s1 + "\r\n" + s2 + "\r\n" + s3 + "\r\n" + s4 + "\r\n" + s5+"\r\n\r\n" +year+ "\r\n\r\n" + rec;
dlg->editt.SetWindowText(dlg->editstr);
int pos;
CString rr;
for (int i = 0; i < 11; i++)
{
pos = rec.Find(';');
rr = rec.Mid(pos + 1, rec.GetLength());
re[i] = rec.Left(pos);
rec = rr;
}
CWnd * pWnd = dlg->GetDlgItem(IDC_STATIC1);
CDC * dc = pWnd->GetDC();//注意这里获取了新的 dc
pWnd->Invalidate();
pWnd->UpdateWindow();
CRect rectView;
CRgn rgn;
dlg->GetDlgItem(IDC_STATIC1)->GetClientRect(&rectView);
rgn.CreateRectRgn(rectView.left, rectView.top, rectView.right, rectView.bottom);
dc->SelectClipRgn(&rgn);
CPen pNewPen(PS_SOLID, 2, RGB(0, 0, 0));
CPen *pOldPen;
pOldPen = dc->SelectObject(&pNewPen);
CBrush pNewBrush1(RGB(255, 255, 0));
CBrush *pOldBrush;
if (re[3] == 'R')
{
CRect rect1(_ttoi(re[4]), _ttoi(re[5]), _ttoi(re[6]), _ttoi(re[7]));
CBrush pNewBrush1(RGB(_ttoi(re[8]), _ttoi(re[9]), _ttoi(re[10])));
dc->Rectangle(&rect1);
pOldBrush = dc->SelectObject(&pNewBrush1);
dc->Rectangle(&rect1);
dc->SelectObject(pOldPen);//恢复原有的笔
dc->SelectObject(pOldBrush);
dc->DeleteDC();
}
if (re[3] == 'E')
{
CRect rect1(_ttoi(re[4]), _ttoi(re[5]), _ttoi(re[6]), _ttoi(re[7]));
CBrush pNewBrush1(RGB(_ttoi(re[8]), _ttoi(re[9]), _ttoi(re[10])));
dc->Ellipse(&rect1);
pOldBrush = dc->SelectObject(&pNewBrush1);
dc->Ellipse(&rect1);
dc->SelectObject(pOldPen);//恢复原有的笔
dc->SelectObject(pOldBrush);
dc->DeleteDC();
}
break;
}
return 0;
}
这里我们不仅实现了从客户端接受信息还可以将其显示在我们的对应的编辑框中,其此,我们还可以根据客户端的请求进行画图,这里请参考本博主的其他文章有详细介绍关于画图及其移动的相关介绍,这里我们要注意的是我们需要用“;”来当做分隔符,你也可以选择别的进行这取决你了。
注:本博客纯原创,如需转载请告诉博主哦!