MFC Socket实现异步接受消息(MFC消息)

直接上代码

编写Socket服务端代码

启动服务端监听

//Socket========================================================================>>>
//绑定监听
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(5555);
serveraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(server, (sockaddr*)&serveraddr, sizeof(serveraddr));
listen(server, 1);

//获取窗口句柄
HWND hWnd = AfxGetMainWnd()->GetSafeHwnd();
//启动异步选择模型     参数:server=套接字对象,hWnd=活动窗口句柄,WM_SOCKET=消息函数,FD_ACCEPT | FD_READ | FD_CLOSE = socket事件
WSAAsyncSelect(server, hWnd, WM_SOCKET, FD_ACCEPT | FD_READ | FD_CLOSE);
//WSAEventSelect(server,hWnd,WM_SOCKET);
//Socket========================================================================>>>

添加Socket响应消息函数

点击vs工具栏中的视图=>类视图(显示类视图目录菜单)=>右键添加消息的窗口类=>类向导
在这里插入图片描述
进入类向导=>进入消息选项卡页面中=>添加自定义消息
在这里插入图片描述
在自定义消息中加入MW_SOCKET,消息处理程序名称会自动填入,随后点击确定即可,在消息中的现有处理程序下的函数名中双击刚刚添加的OnSocket即可进入消息函数体中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pwweDkDG-1597301108023)(MFC Socket实现异步接受消息.assets/image-20200721150915655.png)]

编写消息接收函数代码

.h

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WM_SOCKET WM_USER+1

.cpp

#include <string>
using namespace std;
#include <iostream>
#include <map>

//异步消息
//发生一个网络事件    此函数需要在窗口中添加 WM_SOCKET 消息,消息名称就是:WM_SOCKET   
//mfc中添加自定义消息步骤:项目类视图=>右键要添加消息的窗体类文件见=>类向导=>消息=>添加自定义消息,添加完之后,双击添加的函数名即可定位到添加的类消息中
//#define _WINSOCK_DEPRECATED_NO_WARNINGS
//#define WM_SOCKET WM_USER+1
afx_msg LRESULT CMainFrame::OnSocket(WPARAM wParam, LPARAM lParam)
{
	if (WSAGETASYNCERROR(lParam))
	{
		closesocket(wParam);
		return -1;
	}
	SOCKET client;
	sockaddr_in clientaddr;
	int len = sizeof(clientaddr);
	std::string recvdata, str;
	char buffer[1024] = { 0 };
	int ret = 0;
	HWND hWnd = AfxGetMainWnd()->GetSafeHwnd();

	switch (WSAGETSELECTEVENT(lParam))
	{
	case FD_ACCEPT://注册套接字(有客户机连接时出发)
		client = accept(wParam, (sockaddr*)&clientaddr, &len);
		//s2addr[client] = clientaddr;
		str = inet_ntoa(clientaddr.sin_addr);
		_itoa_s(client, buffer, 10);
		str.append(buffer).append("connected...");
		::MessageBox(NULL, str.c_str(), "提示", MB_OK);

		//检查是否有数据到来
		WSAAsyncSelect(client, hWnd, WM_SOCKET, FD_READ | FD_CLOSE);
		break;
	case FD_READ://读取套接字信息(接收到消息时触发)
		ret = recv(wParam, buffer, 1023, 0);
		buffer[ret] = '\0';
		recvdata = buffer;
		if (recvdata == "quit")
		{
			client = accept(wParam, (sockaddr*)&clientaddr, &len);
			str = inet_ntoa(clientaddr.sin_addr);
			_itoa_s(wParam, buffer, 10);
			str.append(buffer).append("connected...");
			::MessageBoxA(NULL, str.c_str(), NULL, MB_OK);
			closesocket(wParam);
		}
		else
		{
			client = accept(wParam, (sockaddr*)&clientaddr, &len);
			str = inet_ntoa(clientaddr.sin_addr);
			_itoa_s(wParam, buffer, 10);
			str.append(buffer);
			::MessageBoxA(NULL, recvdata.c_str(), str.c_str(), MB_OK);
		}
		break;
	case FD_CLOSE://关闭套接字
		closesocket(wParam);
		break;
	default:
		break;
	}
	return 0;
}

服务器端可实现多客户端连接和接收消息而不阻塞程序运行!

Client端

用于测试服务端是不是异步的,简单的使用控制台程序编写客户端!

(1)加载套接字库,创建套接字
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")

void init();

int main()
{
//创建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
}

void init() {
	//初始化套接字库
	WORD w_req = MAKEWORD(2, 2);//版本号
	WSADATA wsadata;
	int err;
	err = WSAStartup(w_req, &wsadata);
	if (err != 0) {
		cout << "初始化套接字库失败!" << endl;
	}
	else {
		cout << "初始化套接字库成功!" << endl;
	}
	//检测版本号
	if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
		cout << "套接字库版本号不符!" << endl;
		WSACleanup();
	}
	else {
		cout << "套接字库版本正确!" << endl;
	}
}
(2)向服务器发出连接请求(connect());
if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
		cout << "服务器连接失败!" << endl;
		WSACleanup();
	}
	else {
		cout << "服务器连接成功!" << endl;
	}
(3)和服务器进行通信(send()/recv());
//发送,接收数据
	while (1) {
		cout << "请输入发送信息:";
		cin >> send_buf;
		send_len = send(s_server, send_buf, 100, 0);
		if (send_len < 0) {
			cout << "发送失败!" << endl;
			break;
		}
		recv_len = recv(s_server, recv_buf, 100, 0);
		if (recv_len < 0) {
			cout << "接受失败!" << endl;
			break;
		}
		else {
			cout << "服务端信息:" << recv_buf << endl;
		}

}
(4)关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())
//关闭套接字
	closesocket(s_server);
	//释放DLL资源
	WSACleanup();

报错解决方案

WSAAsyncSelect(server, hWnd, WM_SOCKET, FD_ACCEPT);WSAAsyncSelect引起错误
inet_ntoa(clientaddr.sin_addr);inet_ntoa引起错误

错误信息:

Error C4996	
'inet_ntoa': Use inet_ntop() or InetNtop() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings

此错误是指inet_ntoa已过时,如需继续使用请加宏,解决方法有如下两种:

  1. 在代码中添加宏:#define _WINSOCK_DEPRECATED_NO_WARNINGS
  2. 右键项目=>属性=>C/C++=>SDL检查=>否(/sdl-)或者为空
  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值