基于VS2010 MFC创建客户端与服务器窗口,并实现连接和简单通信
一、创建MFC工程和套接字对象
1.创建客户端工程
创建MFC工程名称ChatClient
保存为位置自己选择,点击确定,再点击下一步,选择基于对话框。
点击下一步直到高级功能,勾选套接字:
点击下一步,选择生成APP,再点击完成,就创建好工程了。
2.接下来创建类名为CClientSocket的客户Socket对象,项目/类向导/添加类/MFC类,基类为CAsyncSocket
点击完成,在类视图中可查看添加的类:
在解决方案管理器中可查看所有源文件:
3.要使客户端程序能够创建和控制本地的Socket,在客户端工程界面控制模块的头文件ChatClientDlg.h中添加如下代码:
#include "ClientSocket.h" //使主界面程序能够访问Socket类的代码文件
CClientSocket m_ClientSocket;//为了后面与服务器通信而定义的Socket成员变量
反过来要使Socket能够访问到主页面上的控件,也需要在Socket源文件ClientSocket.cpp中添加头文件声明:
#include "ChatClientDlg.h"
3.打开ChatClient.rc文件夹中Dialog中第二个文件,删除对话框上所有东西:
找到右边工具箱,添加四个类型控件:
添加完如下:
修改按钮名称(右键按钮,点击属性,找到右边caption可以修改):
修改完之后:
4.为控件添加变量
(1)为IP地址控件添加变量ServerIP;选中IP地址控件,右键添加变量
(2)为第一个文本框控件添加int型变量sPort:
(3)为列表框添加变量m_ListWords
(4)为第二个文本框添加CString 型 m_sWords变量
运行代码看有没有报错,没有报错如下:
二、服务器端工程创建
同理服务器端创建跟客服端创建类似:
1.创建名为ChatServer的MFC工程:
选中基于对话框,高级功能勾选套接字。
2.接下来创建类名为CListenSocket和CServerSocket的客户Socket对象,项目/类向导/添加类/MFC类,基类为CAsyncSocket
在类视图中可以查看添加的类:
在解决方案中就可以看到所有源文件:
3.要使服务器端程序能够创建和控制本地Socket,也要在服务端工程界面控制模块头文件ChatServerDlg.h中添加以下代码:
#include "ListenSocket.h" //使主界面程序能够访问监听Socket类的代码文件
#include "ServerSocket.h" //使主界面程序能够访问服务Socket类的代码文件
CServerSocket m_ServerSocket; //为了后面与客户通信而定义的Socket成员变量
CListenSocket m_ListenSocket; //为了监听客户端的连接请求而定义的Socket成员变量
反过来要使Socket能够访问到主页面上的控件,也需要在Socket源文件ServerSocket.cpp中添加头文件声明:
#include "ChatServerDlg.h"
3.打开ChatServer.rc文件夹中Dialog中第二个文件,删除对话框上所有东西:
找到右边工具箱,添加四个类型控件:
添加并修改按钮名称如下:
4.为控件添加变量
同理,和客户端一样分别为IP地址控件(ServerIP),第一个文本框控件(int型,sPort),第二个文本框控件(CString型,m_sWords)和列表框控件(m_ListWords)添加变量:
运行代码看有没有报错,没有报错如下:
到此客户端——服务器程序雏形已经形成
三、程序源代码组织
通信流程图:
四、源代码剖析(双向通信)
1.客户端源码
连接服务器按钮代码(双击按钮添加代码):
//连接服务器
BYTE nFild[4];
CString sIP;
UpdateData();
ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);
sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);
m_ClientSocket.Create(); //创建客户端Socket
m_ClientSocket.Connect(sIP,sPort); //发起连接请求
这里有个红点报错:
这时点击项目/属性/配置属性/常规/字符集/使用多字节字符集
就解决了:
客户端发送按钮代码(双击发送按钮添加代码):
// TODO: 在此添加控件通知处理程序代码
//向服务器发信息
UpdateData();
m_ClientSocket.Send(m_sWords,m_sWords.GetLength()); //发信息
m_ListWords.AddString("发送:" + m_sWords);
m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);
断开服务器按钮代码:
//断开与服务器的连接
m_ClientSocket.Close(); //关闭客户端Socket
m_ListWords.AddString("从服务器断开");
在类视图中选中CClientSocket,在界面右上角点击“重写”按钮,就可以为该Socket类编写响应网络事件的函数
点击增加onconnect函数:
就会跳转到onconnect函数,添加代码如下:
//确认客户端是否成功连接到服务器
if(nErrorCode)
{
AfxMessageBox("连接失败,请您重试!");
return;
}
((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("连接服务器成功!");
((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(
((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()- 1);
击增加onreceive函数,添加代码:
char szTemp[200];
int n = Receive(szTemp,200);
szTemp[n] = '\0';
CString sTemp;
sTemp.Format("收到:%s",szTemp);
((CChatClientDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString(sTemp);
((CChatClientDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(
((CChatClientDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount() - 1);
点击增加on close函数,添加代码:
((CChatClientDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("服务器端断开了");
((CChatClientDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(
((CChatClientDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);
Close();
2.服务器端源码:
开始监听按钮代码(双击开始监听按钮添加代码):
//监听开始,服务器等待连接请求的到来
BYTE nFild[4];
CString sIP,sP;
UpdateData();
ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);
sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);
sP.Format("%d",sPort);
m_ListenSocket.Create(sPort,1,FD_ACCEPT,sIP); //创建服务端监听Socket
m_ListenSocket.Listen(1); //开始监听
m_ListWords.AddString("监听开始:");
m_ListWords.AddString("地址" + sIP + " 端口" + sP);
m_ListWords.AddString("等待客户端连接……");
在类视图中选中CServerSocket,在界面右上角点击“重写”按钮,就可以为该Socket类编写响应网络事件的函数
点击增加on receive函数,添加代码如下:
//接收客户端发来的信息
char szTemp[200];
int n = Receive(szTemp,200); //接收信息
szTemp[n] = '\0';
CString sTemp;
sTemp.Format("收到:%s",szTemp);
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString(sTemp);
//显示信息
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount() - 1);
点击增加on close函数,添加代码如下:
//关闭与客户端的通信信道
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("客户端断开连接");
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);
Close(); //关闭与客户端通信的Socket
在类视图中选中CListenSocket,在界面右上角点击“重写”按钮,就可以为该Socket类编写响应网络事件的函数
点击增加on Accept函数,添加代码如下:
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("接收到客户端的一个连接请求!");
//显示信息
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(
((CChatServerDlg *)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount() - 1);
双击击服务器端发送按钮添加代码:
UpdateData();
m_ServerSocket.Send(m_sWords,m_sWords.GetLength());
m_ListWords.AddString("发送:" + m_sWords);
m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);
双击断开按钮,添加代码:
m_ServerSocket.Close();
m_ListWords.AddString("与客户端断开");
3.同时运行客户端和服务器端程序
运行结果:
端口号不同:
端口号相同:
最后附上完整教程PPT链接:
链接: https://pan.baidu.com/s/1yOpdM9hgqQGNyekD6nRv2g 提取码: xwx5