MFC下客户端与服务器端的Socket通信

基于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

  • 22
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值