网络编程 异步选择模型

news2024/11/16 5:44:46

目录

1.概念

 2.代码样例


1.概念

        基本概念,在这一个模型中的代码使用到了vs中窗口应用程序,可以看这一片文章https://blog.csdn.net/weixin_62859191/article/details/128415737?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_62859191/article/details/128415737?spm=1001.2014.3001.5501

 2.代码样例

        代码实现的流程

        在这里使用了vs的窗口信息,代码可以在上面的链接中去拿,在异步选择模型中代码主要的区别是函数WSAAsyncSelect,该函数把事件和socket绑定并且投递给系统,函数原型

int WSAAPI WSAAsyncSelect(
  [in] SOCKET s,
  [in] HWND   hWnd,
  [in] u_int  wMsg,
  [in] long   lEvent
);

参数1 s:需要绑定的客户端socket

参数2 HWND:控制台窗口的句柄

参数3 wMsg:客户端发出的消息

参数4 lEvent:投递的事件

        返回值:成功返回0,失败返回SOCKET_ERROR

##代码实例

在代码中,把事件进行分类处理都需要在窗口的回调函数中实现,回调函数中的第三个参数可以获取到服务器的socket

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include<stdio.h>
#include<Winsock2.h>
#pragma comment(lib, "ws2_32.lib")

#define UM_ANYNCSELECT WM_USER+1//WM_USER表示系统处理消息所占数量,在这之后就是客户端的消息
//定义一个数组记录socket
#define MAX_SOCK_COUNT 1024
SOCKET fd_socket[MAX_SOCK_COUNT];
int sock_count = 0;
int y = 0;//让输出的位置不断往下移

LRESULT CALLBACK WinBackProc(HWND hWnd, UINT msgID, WPARAM wparam, LPARAM lparam);//窗口的回调函数
SOCKET SocketServer();//把网络库封装成函数

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nShowCmd)
{
	//第一步 创建结构体窗口
	WNDCLASSEX wc;
	wc.cbClsExtra = 0;//类的额外空间
	wc.cbWndExtra = 0;//窗口的额外空间
	wc.cbSize = sizeof(WNDCLASSEX);//窗口大小
	wc.hbrBackground = NULL; //背景颜色
	wc.hCursor = NULL;//鼠标图标
	wc.hIcon = NULL;//左上角图标
	wc.hIconSm = NULL;//任务栏图标
	wc.hInstance = hInstance;//窗口句柄
	wc.lpfnWndProc = WinBackProc;//回调函数
	wc.lpszClassName = "异步选择模型";//窗口名称
	wc.lpszMenuName = NULL;//菜单栏名称
	wc.style = CS_HREDRAW | CS_VREDRAW;//窗口风格 可以水平和垂直拉伸

	//第二步 注册结构体
	RegisterClassEx(&wc);

	//第三步 创建窗口
	HWND hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "异步选择模型", "async", WS_OVERLAPPEDWINDOW, 200, 200, 800, 600,
		NULL, NULL, hInstance, NULL);
	if (hWnd == NULL)
	{
		return 0;
	}

	//第四步 显示窗口
	ShowWindow(hWnd, nShowCmd);

	//更新窗口
	UpdateWindow(hWnd);

	//创建socket
	SOCKET socketServer = SocketServer();
	//绑定事件和socket
	if (SOCKET_ERROR == WSAAsyncSelect(socketServer, hWnd, UM_ANYNCSELECT, FD_ACCEPT))//成功返回0,出错返回SOCKET_ERROR
	{
		closesocket(socketServer);
		WSACleanup();
		return 0;
	}
	//记录socket
	fd_socket[sock_count] = socketServer;
	sock_count++;

	//第五步 消息循环
	MSG msg;//结构体
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);//把获取到的消息翻译成代码,就是字符串
		DispatchMessage(&msg);//把消息分发
	}

	for (int i = 0; i < sock_count; i++)
	{
		closesocket(fd_socket[i]);
	}
	WSACleanup();
	return 0;
}

//回调函数
LRESULT CALLBACK WinBackProc(HWND hWnd, UINT msgID, WPARAM wparam, LPARAM lparam)
{
	HDC hdc = GetDC(hWnd);//获取窗口的画布信息
	switch (msgID)
	{
	case UM_ANYNCSELECT://在switch里是不可以直接定义变量的
	{
		//MessageBox(NULL, L"有信号连接", L"提示窗口", MB_OK);
		//获取socket
		SOCKET sock = (SOCKET)wparam;
		//获取消息
		if (0 != HIWORD(lparam))//lparam存放的时是客户端触发的消息,使用HIWORD可以判断消息是否正确
		{
			if (WSAECONNABORTED == HIWORD(lparam))
			{
				TextOut(hdc, 0, y, "close", (int)strlen("close"));
				y += 15;
				//关闭socket上的消息
				WSAAsyncSelect(sock, hWnd, 0, 0);//把后面两个参数置为0即为删除
				//删除数组中的socket
				for (int i = 0; i < sock_count; i++)
				{
					if (sock == fd_socket[i])
					{
						fd_socket[i] = fd_socket[sock_count - 1];
						sock_count--;
						break;
					}
				}
				//关闭socket
				closesocket(sock);
			}
			break;
		}
		//具体消息
		switch (LOWORD(lparam))//可以获取到具体的消息
		{
		case FD_ACCEPT://有请求连接
		{
			SOCKET socketClient = accept(sock, NULL, NULL);
			if (socketClient == INVALID_SOCKET)
			{
				printf("创建客户端socket失败\n");
				//出错了
				int a = WSAGetLastError();
				break;
			}
			//绑定客户端信息,将客户端投递给消息队列
			if (SOCKET_ERROR == WSAAsyncSelect(socketClient, hWnd, UM_ANYNCSELECT, FD_READ | FD_WRITE | FD_CLOSE))
			{
				//出错了
				int a = WSAGetLastError();
				closesocket(socketClient);
				break;
			}
			TextOut(hdc, 0, y, "accept succee", (int)strlen("accept succee"));//在窗口输出信息
			y += 15;
			//记录socket
			fd_socket[sock_count] = socketClient;
			sock_count++;
		}
			break;
		case FD_READ:
		{
			TextOut(hdc, 0, y, "read:", (int)strlen("read:"));
			char buf[1500] = { 0 };
			if (SOCKET_ERROR == recv(sock, buf, 1499, 0))
			{
				int a = WSAGetLastError();
				break;
			}
			TextOut(hdc, 35, y, buf, (int)strlen(buf));
			y += 15;
		}
			break;
		case FD_WRITE:
			TextOut(hdc, 0, 15, "write", (int)strlen("write"));
			y += 15;
			break;
		case FD_CLOSE:
			TextOut(hdc, 0, y, "close", (int)strlen("close"));
			y += 15;
			//关闭socket上的消息
			WSAAsyncSelect(sock, hWnd, 0, 0);//把后面两个参数置为0即为删除
			//删除数组中的socket
			for (int i = 0; i < sock_count; i++)
			{
				if (sock == fd_socket[i])
				{
					fd_socket[i] = fd_socket[sock_count - 1];
					sock_count--;
					break;
				}
			}
			//关闭socket
			closesocket(sock);
			break;
		}
	}
		break;
	case WM_CREATE://初始化 只执行一次
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	ReleaseDC(hWnd,hdc);//释放窗口画布信息
	return DefWindowProc(hWnd, msgID, wparam, lparam);//默认处理消息的函数
}

SOCKET SocketServer()
{
	//第一步 打开网络库并校验版本
	WORD wdVersion = MAKEWORD(2, 2);
	WSADATA wdSocketMsg;
	int nRes = WSAStartup(wdVersion, &wdSocketMsg);
	if (nRes != 0)
	{
		printf("打开网络库失败\n");
		return 0;
	}
	if (HIBYTE(wdSocketMsg.wVersion) != 2 || LOBYTE(wdSocketMsg.wVersion) != 2)
	{
		printf("网络库版本出错\n");
		WSACleanup();
		return 0;
	}
	//第二步 创建socket
	SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (socketServer == INVALID_SOCKET)
	{
		printf("创建的socket无效\n");
		WSACleanup();
		return 0;
	}
	//第三步 绑定ip地址和端口号
	struct sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12332);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	if (SOCKET_ERROR == bind(socketServer, (const struct sockaddr*)&si, sizeof(si)))
	{
		printf("绑定失败\n");
		closesocket(socketServer);
		WSACleanup();
		return 0;
	}
	//第四步 开始监听
	if (SOCKET_ERROR == listen(socketServer, SOMAXCONN))
	{
		printf("监听失败\n");
		closesocket(socketServer);
		WSACleanup();
		return 0;
	}
	return socketServer;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/126121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

站在2023起跑线,政企数字化如何深入“核心地带”?

今天&#xff0c;各行各业都积极开展数字化变革&#xff0c;以云为底座开展数字化已成为行业共识。而更进一步观察会发现&#xff0c;大型政企作为数字化转型的先行者和主力军&#xff0c;已经从资源上云、应用上云阶段&#xff0c;率先抵达了数字化深水区&#xff0c;迈入了深…

UDS-Data transmission functional unit

11 数据传输功能单元 11.1 概述 表185指定了数据传输功能单元。 注&#xff1a; ReadDataByIdentifier&#xff1a;客户端通过提供的dataIdentifier去请求读取标识记录的当前值。ReadMemoryByAddress&#xff1a;客户端请求读取所提供的内存范围的当前值。ReadScalingData…

机器学习100天(十九):019 分类模型评价指标-混淆矩阵

机器学习100天,今天讲的是:分类模型评价指标-混淆矩阵。 《机器学习100天》完整目录:目录 一、准确率(Accuracy) 逻辑回归是一个分类模型,那么对于分类模型,如何评估它的优劣呢? 好,我们先来认识一个名词:混淆矩阵(confusion matrix)。混淆矩阵是用来衡量一个分…

C语言预处理器

C 预处理器不是编译器的组成部分&#xff0c;但是它是编译过程中一个单独的步骤。简言之&#xff0c;C 预处理器只不过是一个文本替换工具而已&#xff0c;它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器&#xff08;C Preprocessor&#xff09;简写为 …

pybind11学习 | 使用CMake构建系统并生成pyd文件

文章目录一 通过Visual Studio生成二 通过CMake生成一 通过Visual Studio生成 在我之前的一篇文章pybind11学习 | VS2022下安装配置中&#xff0c;描述了如何通过配置VS2022实现pybind11项目构建和编译成Python拓展模块。 二 通过CMake生成 项目结构如下&#xff1a; 其中py…

(二十七)Vue组件的样式

文章目录scoped属性实现原理lang属性样式穿透Vue学习目录 上一篇&#xff1a;&#xff08;二十六&#xff09;Vue之插件 scoped属性 scoped 属性是 HTML5 中的新属性。如果使用该属性&#xff0c;则样式仅仅应用到 style 元素的父元素及其子元素。即让样式在局部生效&#x…

kafka多线程消费

Kafka consumer 多线程消费 kafka 消费者对象 - KafkaConsumer是非线程安全的。与KafkaProducer不同&#xff0c;KafkaProducer是线程安全的&#xff0c;因为开发者可以在多个线程中放心地使用同一个KafkaProducer实例。 但是对于消费者而言&#xff0c;由于它是非线程安全的…

FreeFileSync 11.29 发布

导读FreeFileSync 是一款开源软件&#xff0c;适用于 Windows、macOS 和 Linux。FreeFileSync 本质是一个用于文件夹对比和同步的软件&#xff0c;它可以创建和管理所有重要文件的备份副本。FreeFileSync 不是每次都复制每个文件&#xff0c;而是确定源文件夹和目标文件夹之间的…

使用 ClusterResourceSet 为 Cluster API 集群自动安装 CNI 插件

1 什么是 Cluster API Cluster API[1] 是一个 Kubernetes 子项目&#xff0c;它将声明式、Kubernetes 风格的 API 引入到集群的创建、配置和管理中。Cluster API 支持在 AWS, Azure, GCP, vSphere, KubeVirt 等多种环境中创建和管理 Kuberenetes 集群&#xff0c;并负责提供部…

单例(Singleton)设计模式

一、单例(Singleton)设计模式说明 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典的棋谱&#xff0c;不同的棋局&#xff0c;我们用不同的棋谱&#xff0c;"套路"所谓类…

WebView以及使用HTTP访问访问网络

文章目录使用网络技术WebView的用法使用HTTP访问网络使用HttpURLConnection使用OkHttp使用网络技术 在Android开发当中,我们应该合理的使用网络编写出更加出色的应用程序,下面学习以下如何在手机端使用HTTP和服务器进行网络交互,并对服务器返回的数据进行解析,这也是在Android…

爽啊,这么多有趣好玩强大的 Python 库

Python语言简洁、易读以及可扩展&#xff0c;在国内外用 Python 做研究的非常多。 Python 语言向来以丰富的第三方库而闻名。这么多有趣好玩且强大&#xff0c;靠一个人去寻找太难了。 最近粉丝群小伙伴们又罗列了一些&#xff0c;分享给大家。喜欢记得点个赞&#xff0c;加入…

OpenHarmony#深入浅出学习eTs#(三)UI布局

本项目Gitee仓地址&#xff1a;深入浅出eTs学习: 带大家深入浅出学习eTs (gitee.com) 一、ArkUI介绍 框架介绍 方舟开发框架&#xff08;简称&#xff1a;ArkUI&#xff09;&#xff0c;是一套UI开发框架&#xff0c;提供开发者进行应用UI开发时所必需的能力。 基本概念 组…

力扣sql入门篇(二)

力扣sql入门篇(二) 1 计算特殊奖金 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT employee_id, case when employee_id%21 AND name not like "M%" then salary else 0 end bonus FROM Employees ORDER BY employee_id;1.3 运行…

【软件测试】测试人的一份“漂亮“的年终总结报告......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 不管这一年&#xf…

举一反三-自建zabbix监控mysql

之前写过2篇zabbix监控redis的文章。 本篇针对的是mysql。除了描述如何创建mysql监控的步骤,本篇另一个目的是描述创建任意一个监控对象的基本原理,未来面对其它监控对象时,可以举一反三。 zabbix监控的最基本的部件时zabbix server和zabbix agent. zabbix server负责汇总…

c++primer 第4章 表达式

文章目录第4章 表达式4.1 基础4.1.1 基础概念4.1.2 优先级与结合律4.1.3 求值顺序4.2 算术运算符4.3 逻辑和关系运算符4.4 赋值运算符4.5 递增和递减运算符4.6 成员访问运算符4.7 条件运算符4.8 位运算符4.9 sizeof运算符4.10 逗号运算符4.11 类型转换4.11.1 算术转换4.11.2 其…

ES6-ES11笔记(1)

关于这个视频的笔记 (https://www.bilibili.com/video/BV1uK411H7on?p29&vd_source3cf72bb393b8cc11b96c6d4bfbcbd890) 1.ES6 1.1let的一些注意点 let a; let b,c,d; let e 100; let f"你好",g101;// 变量名不能重复声明 // let testDepulicate 123456 // …

无信息变量消除法研究及实现(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 波长变量筛选的方法主要有相关系数法&#xff0c;逐步回归法&#xff0c;无信息变量消除法(UVE)&#xff0c;遗传算法(genetic …

python圣诞树词云

一、前言 圣诞节虽然是西方节日&#xff0c;但是个人还是比较喜欢的&#xff08;没有崇洋媚外的意思&#xff0c;中国的春节也超级棒&#xff09;&#xff0c;一个是圣诞节的氛围&#xff0c;圣诞节的圣诞老人等象征、雪花麋鹿等元素&#xff0c;都充满了浪漫的氛围。我想这也是…