当前位置: 首页 > news >正文

【第23节】windows网络编程模型(WSAEventSelect模型)

目录

引言

一、WSAEventSelect模型概述 

二、 WSAEventSelect模型的实现流程

2.1 创建一个事件对象,注册网络事件

2.2 等待网络事件发生

2.3 获取网络事件

2.4 手动设置信号量和释放资源

三、 WSAEventSelect模型伪代码示例

四、完整实践示例代码


引言

        在网络编程的复杂世界里,如何高效捕捉和响应网络事件是构建稳健应用的关键。WSAEventSelect模型作为一种强大的异步I/O模型,为开发者开辟了一条独特路径。它借助事件驱动机制,让应用程序能够敏锐感知套接字上的网络动态。与WSAAsyncSelect模型不同,它以事件而非消息形式传递通知,为网络编程带来别样灵活性。接下来,让我们深入探索WSAEventSelect模型的工作原理、实现流程以及实际应用示例。

一、WSAEventSelect模型概述 

        Windows Sockets异步事件选择模型,也就是WSAEventSelect模型,属于另一种异步I/O模型。利用这个模型,应用程序能够在单个或多个套接字上,基于事件接收网络方面的通知。

        WSAEventSelect模型和WSAAsyncSelect模型有所不同,主要区别就在于应用程序接收网络事件通知的方式。WSAEventSelect模型通过事件来告诉应用程序网络事件发生了,而WSAAsyncSelect模型是依靠消息来通知。但从根本上来说,在应用程序接收网络事件通知这件事上,这两个模型都是被动的。意思就是,只有网络事件真正发生的时候,系统才会向应用程序发出通知 。 

二、 WSAEventSelect模型的实现流程

初始化套接字、绑定端口及IP、监听这前三步在此略过。

2.1 创建一个事件对象,注册网络事件

        在应用程序调用WSAEventSelect函数之前,必须先创建一个事件对象。当获取到一个socket后,需使用WSACreateEvent函数来创建事件对象,之后再使用WSAEventSelect函数进行相关操作。

WSAEVENT WSACreateEvent(void);

该函数的返回值为事件对象句柄。

int WSAEventSelect(SOCKET s,             //当前服务端的SOCK句柄WSAEVENT hEventObject, //事件对象句柄long lNetworkEvents   //网络事件
);

         注:当调用WSAEventSelect函数后,套接字会被自动设置为非阻塞模式。若要将套接字设置为阻塞模式,则必须把参数lNetworkEvents设置为0。


示例:

//创建一个事件对象
WSAEVENT wsaEvent = WSACreateEvent();
if (WSA_INVALID_EVENT == wsaEvent) {printf("创建一个事件对象失败!");closesocket(sSocket);WSACleanup();
}
//注册网络事件
if (WSAEventSelect(sSocket,  wsaEvent,  //当前服务端的SOCK句柄//事件对象句柄FD_ACCEPT | FD_CLOSE)) {    //网络事件printf("注册网络事件失败!");closesocket(sSocket);   //关闭套接字WSACleanup();//释放套接字资源return FALSE;
}

2.2 等待网络事件发生

        在WinSockets应用程序里,先用WSAEventSelect函数给套接字把网络事件注册好,紧接着就得调用WSAWaitForMultipleEvents函数,目的是等着网络事件发生。这个WSAWaitForMultipleEvents函数的作用就是,一直等到有一个事件对象或者所有事件对象进入“有信号量”状态,又或者是函数调用时间到了(超时),它才会返回结果 。 

DWORD WSAWaitForMultipleEvents(DWORD cEvents,           //事件对象句柄数量WSAEVENT FAR*lphEvents, //指向事件对象句柄的指针BOOL fWaitAll,           //等待事件句柄的数量DWORD dwTimeout,         //调用该函数的阻塞时间BOOL fAlertable          //完成例程后是否继续等待
);

        WSAWaitForMultipleEvents这个函数,最多能够处理64个对象。所以呢,基于这个情况,使用这个I/O模型的时候,在一个线程里,同一时刻最多也就只能支持64个套接字。要是你想用这个模型去管理超过64个套接字,那就得再创建一些额外的工作线程才行。 

        WSAWaitForMultipleEvents函数的作用就是等着网络事件发生。只要在规定的时间里,有网络事件出现了,那这个函数返回的值,就能告诉你是哪个事件对象导致函数返回的 。 

        注:要是fWaitAll这个参数设成true,那所有的事件对象都会被置为有信号量状态。要是fWaitAll被设成FALSE,那么只要众多事件句柄当中有一个变为有信号量状态就可以了。这个函数运行结束后会给出一个返回值,这个返回值其实是个索引。用这个索引减去WSA_WAIT_EVENT_0这个宏的值,就能够知道在事件数组里,哪个事件被触发了,也就是能找到被触发事件在数组中的位置 。 


示例:

//定义事件对象数组
EventArray[WSA_MAXIMUMWAIT_EVENTS] = {};
//等待网络事件的发生
DWORD dwIndex =
WSAWaitForMultipleEvents(uEventCount, EventArray,  FALSE,
WSA_INFINITE,
FALSE);        
//完成例程后是否继续等待
//返回该事件在EventArray数组中的位置(下标从0开始)
dwIndex = dwIndex - WSA_WAIT_EVENT_0;

2.3 获取网络事件

        利用WSAWaitForMultipleEvents函数的返回值,我们能知道哪个套接字发生了网络事件。不过,仅仅知道是哪个套接字还不够,应用程序还得弄清楚在这个套接字上具体发生了哪种网络事件。WSAEnumNetworkEvents函数就派上用场了,它能找出套接字上发生的网络事件,同时把系统里关于这个网络事件的记录清除掉,还会把事件对象重新设置回初始状态 。

int WSAEnumNetworkEvents(SOCKET s,                          //发生网络事件的套接字句柄WSAEVENT hEventObject,             //被重置的事件对象句柄LPWSANETWORKEVENTS lpNetworkEvents //网络事件的记录和相应错误码
);
typedef struct _WSANETWORKEVENTS {long lNetworkEvents;               //网络事件int iErrorCode[FD_MAX_EVENTS];     //错误码
}

WSAEnumNetworkEvents参数

 _WSANETWORKEVENTS 参数

         使用方式:当lNetworkEvents&FD_XX为TRUE时,即表示发生了此网络事件。


示例:

Socket SocketArray[WSA_MAXIMUM_WAIT_EVENTS] = {};
int uEventCount = 0;                   //记录当前事件和套接字的个数
WSAEnumNetworkEvents(SocketArray[dwIndex],//发生网络事件的套接字句柄
EventArray[dwIndex],//被重置的事件对象句柄
&NetworkEvents))     //网络事件的记录和相应错误码
//响应网络事件
if ((NetworkEvents.lNetworkEvents & FD_ACCEPT) &&0 == NetworkEvents.iErrorCode[FD_ACCEPT_BIT]) {// 处理逻辑
}

        这个函数创建的事件对象,有“手动重设”和“自动重设”这两种工作模式。咱们这里创建的事件对象,是按手动方式工作的,一开始它处于无信号状态。一旦网络事件发生,跟套接字相关联的这个事件对象,就会从无信号量的状态变成有信号量状态。因为是“手动重设”模式,所以应用程序把相关事件处理完之后,得把这个有信号量的事件对象,再变回无信号量状态。 有个MAX_NUM_SOCKET宏,它的值是64 ,一般来说,这代表一个线程最多能同时等待处理64个事件,也就是说一个线程最多只能同时盯着64个socket。要是超过了这个数量,就必须再开启新的线程来处理。 调用这个函数的时候,如果hEventObject参数不是NULL,那么这个事件对象就会被自动重置为“无信号”状态;要是hEventObject参数是NULL,那就得调用WSAResetEvent函数,把事件设置成“无信号”状态 。 

2.4 手动设置信号量和释放资源

BOOL WSAResetEvent(WSAEVENT hEvent //要设置为无信号量的事件对象句柄
);


WSAResetEvent函数用于将事件对象从“有信号量”设置为“无信号量”。

BOOL WSACloseEvent(WSAEVENT hEvent //要释放资源的事件对象句柄
);

        应用程序完成网络事件的处理后,需要使用WSACloseEvent函数释放事件对象所占用的系统资源。

三、 WSAEventSelect模型伪代码示例

#include <Winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
typedef struct _EVENT_SOCKET_INFO {WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];SOCKET SocketArray[WSA_MAXIMUM_WAIT_EVENTS];
}EVENT_SOCKET_INFO, *PEVENT_SOCKET_INFO;
BOOL SetSocket() {//1.初始化套接字WSADATA  stcData;int nResult;nResult = WSAStartup(MAKEWORD(2, 2), &stcData);if (nResult == SOCKET_ERROR)return FALSE;//2.创建套接字// 此处代码省略//3.初始化地址定址sockaddr_in sAddr = {0};sAddr.sin_family = AF_INET;sAddr.sin_port = htons(1234);sAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");int nSaddrLen = sizeof(sockaddr_in);//4.绑定int nRet = 0;nRet = bind(sSocket,(sockaddr*)&sAddr,sizeof  (sockaddr_in));if (SOCKET_ERROR == nRet) {printf("绑定IP定址失败");closesocket(sSocket);WSACleanup();}//接收返回信息//当前客户端SOCK句柄//IP定址//IP定址结构体大小//关闭套接字//释放套接字资源//WSANETWORKEVENTS NetworkEvents = {0};//网络事件的记录和相应错误码SOCKET                            sClientSocket           = 0;  //当前发送事件客户端的SOCK句柄UINT                                 uEventCount           = 0;  //事件对象句柄数量CLIENTINFO                  ClientInfo              = {0};//当前发送事件的客户端EVENT_SOCKET_INFO       EventSocketInfo = {0};//保存事件和Sock信息//5.监听if (listen(sSocket, SOMAXCONN)) {printf("    监听失败!");closesocket(sSocket);WSACleanup();}//6.创建一个事件对象WSAEVENT wsaEvent = WSACreateEvent();if (WSA_INVALID_EVENT == wsaEvent) {printf("创建一个事件对象失败!");closesocket(sSocket);WSACleanup();}//关闭套接字//释放套接字资源//7.注册网络事件if (WSAEventSelect(sSocket,wsaEvent,//当前服务端的SOCK句柄//事件对象句柄FD_ACCEPT | FD_CLOSE))//网络事件{printf("注册网络事件失败!");closesocket(sSocket);WSACleanup();//关闭套接字//释放套接字资源return FALSE;}//保存事件对象和套接字EventSocketInfo.EventArray[uEventCount]      = wsaEvent;EventSocketInfo.SocketArray[uEventCount++] = sSocket;while (TRUE) {WSAEVENT       EventArray[WSA_MAXIMUM_WAIT_EVENTS];//8.等待网络事件的发生DWORD dwIndex = WSAWaitForMultipleEvents(uEventCount,EventSocketInfo.EventArray,FALSE,WSA_INFINITE,FALSE);if (WSA_WAIT_FAILED == dwIndex)continue;//手动设置无信号//WSAResetEvent(EventSocketInfo.EventArray);//9.找到有信号的对象的标号//WSAWaitForMultipleEvent       函数的返回值-WSA_WAIT_EVENT_0dwIndex    = dwIndex - WSA_WAIT_EVENT_0;if (WSAEnumNetworkEvents(EventSocketInfo.SocketArray[dwIndex],//               发生网络事件的套接字句柄EventSocketInfo.EventArray                 [dwIndex],//被重置的事件对象句柄&NetworkEvents))                                               //网络事件的记录和相应错误码{printf("     调用WSAEnumNetworkEvents失败!");closesocket(sSocket);                                      //关闭套接字WSACleanup();                                                         //释放套接字资源}//10.响应网络事件//10.1连接if ((NetworkEvents.lNetworkEvents & FD_ACCEPT) &&0 == NetworkEvents.iErrorCode[FD_ACCEPT_BIT]) {sClientSocket       = accept(sSocket, (sockaddr*)&sAddr, &nSaddrLen);if (INVALID_SOCKET        == sClientSocket) {printf("     连接客户端失败!");continue;}//为新客户端创建网络事件//1.为刚连接进来的客户端创建事件对象EventSocketInfo.EventArray[uEventCount] = WSACreateEvent();//2.保存当前连接进来的客户端Socket 套接字EventSocketInfo.SocketArray[uEventCount] = sClientSocket;//3.为该客户端注册网络事件WSAEventSelect(sClientSocket,EventSocketInfo.EventArray[uEventCount],FD_READ | FD_WRITE                    | FD_CLOSE);uEventCount++;ClientInfo.ClientSock                  = sClientSocket;g_ClientInfo.push_back(ClientInfo);continue;}//10.2接收消息if ((NetworkEvents.lNetworkEvents & FD_READ) &&0        == NetworkEvents.iErrorCode[FD_READ_BIT]) {// 接收数据处理逻辑continue;}//10.3关闭事件if ((NetworkEvents.lNetworkEvents & FD_CLOSE) &&(0 == NetworkEvents.iErrorCode[FD   CLOSE_BIT])) {//关闭Socket套接字和释放事件对象占有的资源closesocket(EventSocketInfo.SocketArray[dwIndex]);WSACloseEvent(EventSocketInfo.EventArray[dwIndex]);//将退出的客户端从事件数组中删除,并将之后的数据向前移动for (int i = dwIndex; i < uEventCount; i++) {  //线性表EventSocketInfo.EventArray[dwIndex]= EventSocketInfo.EventArray[dwIndex + 1];EventSocketInfo.SocketArray[dwIndex]= EventSocketInfo.SocketArray[dwIndex + 1];}uEventCount--;continue;}}return TRUE;
}

        WSAEventSelect模型作为一种异步I/O模型,通过事件机制实现网络事件的通知与处理,在网络编程中为应用程序提供了一种有效的处理网络操作的方式,了解其原理和实现流程有助于开发者编写出更高效、稳定的网络应用程序。

四、完整实践示例代码

头文件initsock.h:

#include <winsock2.h>
#pragma comment(lib, "WS2_32")  // 链接到 WS2_32.libclass CInitSock
{
public:/*CInitSock 的构造器*/CInitSock(BYTE minorVer = 2, BYTE majorVer = 2){// 初始化WS2_32.dllWSADATA wsaData;WORD sockVersion = MAKEWORD(minorVer, majorVer);if (::WSAStartup(sockVersion, &wsaData) != 0){exit(0);}}/*CInitSock 的析构器*/~CInitSock(){::WSACleanup();}
};

 服务端代码:

#include "initsock.h"
#include <iostream>
using namespace std;// 初始化Winsock库
CInitSock theSock;int main()
{// 事件句柄和套节字句柄表WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];SOCKET    sockArray[WSA_MAXIMUM_WAIT_EVENTS];int nEventTotal = 0;// 创建监听套节字SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(4567);    // 此服务器监听的端口号sin.sin_addr.S_un.S_addr = INADDR_ANY;if (::bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR){cout << " Failed bind()" << endl;return -1;}// 进入监听模式if (::listen(sListen, 5) == SOCKET_ERROR){cout << " Failed listen()" << endl;return 0;}cout << "服务器已启动监听,可以接收连接!" << endl;// 创建事件对象,并关联到新的套节字WSAEVENT event = ::WSACreateEvent();::WSAEventSelect(sListen, event, FD_ACCEPT | FD_CLOSE);// 添加到表中eventArray[nEventTotal] = event;sockArray[nEventTotal] = sListen;nEventTotal++;// 处理网络事件while (TRUE){// 在所有事件对象上等待int nIndex = ::WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE);// 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态nIndex = nIndex - WSA_WAIT_EVENT_0;for (int i = nIndex; i < nEventTotal; i++){nIndex = ::WSAWaitForMultipleEvents(1, &eventArray[i], TRUE, 1000, FALSE);if (nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT){continue;}else{// 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件WSANETWORKEVENTS event;::WSAEnumNetworkEvents(sockArray[i], eventArray[i], &event);if (event.lNetworkEvents & FD_ACCEPT)                // 处理FD_ACCEPT通知消息{if (event.iErrorCode[FD_ACCEPT_BIT] == 0){if (nEventTotal > WSA_MAXIMUM_WAIT_EVENTS){cout << " Too many connections!" << endl;continue;}sockaddr_in addrRemote;int nAddrLen = sizeof(addrRemote);SOCKET sNew = ::accept(sockArray[i], (SOCKADDR*)&addrRemote, &nAddrLen);cout << "\n与主机" << ::inet_ntoa(addrRemote.sin_addr) << "建立连接" << endl;WSAEVENT event = ::WSACreateEvent();::WSAEventSelect(sNew, event, FD_READ | FD_CLOSE | FD_WRITE);// 添加到表中eventArray[nEventTotal] = event;sockArray[nEventTotal] = sNew;nEventTotal++;}}else if (event.lNetworkEvents & FD_READ)         // 处理FD_READ通知消息{if (event.iErrorCode[FD_READ_BIT] == 0){char szText[256];int nRecv = ::recv(sockArray[i], szText, strlen(szText), 0);if (nRecv > 0){szText[nRecv] = '\0';cout << "  接收到数据:" << szText << endl;}// 向客户端发送数据char sendText[] = "你好,客户端!";if (::send(sockArray[i], sendText, strlen(sendText), 0) > 0){cout << "  向客户端发送数据:" << sendText << endl;}}}else if (event.lNetworkEvents & FD_CLOSE)        // 处理FD_CLOSE通知消息{if (event.iErrorCode[FD_CLOSE_BIT] == 0){::closesocket(sockArray[i]);for (int j = i; j < nEventTotal - 1; j++){eventArray[j] = eventArray[j + 1];sockArray[j] =  sockArray[j + 1];}nEventTotal--;}}}}}return 0;
}

客户端代码:

#include "InitSock.h"
#include <iostream>
using namespace std;CInitSock initSock;     // 初始化Winsock库int main()
{// 创建套节字SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (s == INVALID_SOCKET){cout << " Failed socket()" << endl;return 0;}// 也可以在这里调用bind函数绑定一个本地地址// 否则系统将会自动安排char address[20] = "127.0.0.1";// 填写远程地址信息sockaddr_in servAddr;servAddr.sin_family = AF_INET;servAddr.sin_port = htons(4567);// 注意,这里要填写服务器程序(TCPServer程序)所在机器的IP地址// 如果你的计算机没有联网,直接使用127.0.0.1即可servAddr.sin_addr.S_un.S_addr = inet_addr(address);if (::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1){cout << " Failed connect() " << endl;return 0;}else {cout << "与服务器 " << address << "建立连接" << endl;}char szText[] = "你好,服务器!";if (::send(s, szText, strlen(szText), 0) > 0){cout << "  发送数据:" << szText << endl;}// 接收数据char buff[256];int nRecv = ::recv(s, buff, 256, 0);if (nRecv > 0){buff[nRecv] = '\0';cout << "  接收到数据:" << buff << endl;}// 关闭套节字::closesocket(s);return 0;
}

相关文章:

【第23节】windows网络编程模型(WSAEventSelect模型)

目录 引言 一、WSAEventSelect模型概述 二、 WSAEventSelect模型的实现流程 2.1 创建一个事件对象&#xff0c;注册网络事件 2.2 等待网络事件发生 2.3 获取网络事件 2.4 手动设置信号量和释放资源 三、 WSAEventSelect模型伪代码示例 四、完整实践示例代码 引言 在网…...

C# 中实现 跨线程写入

方案核心思路 写入请求队列&#xff1a;使用 ConcurrentQueue 接收来自任意线程的写入请求。 专用写入线程&#xff1a;由独立线程处理队列中的写入操作&#xff0c;确保顺序执行。 双信号机制&#xff1a;通过 ManualResetEventSlim 控制读取线程的暂停与恢复。 线程安全确…...

联合体(Union)的使用与应用场景

引言 在 C/C++ 编程中,联合体(Union)是一个非常独特的数据结构。与结构体(struct)不同,联合体允许不同的数据类型共享同一块内存空间,从而节省内存。在许多需要高效内存管理的场景下,联合体的使用能够显著提高程序的性能与资源利用率。本文将从联合体的基本概念入手,…...

Spark2 之 Expression/Functions

ExpressionConverter src/main/scala/org/apache/gluten/expression/ExpressionConverter.scala TopNTransformer src/main/scala/org/apache/gluten/execution/TopNTransformer.scala...

【Mysql】SQL 优化全解析

文章目录 一、理解执行计划​1.1 执行计划的作用​1.2 查看执行计划​ 二、查询优化​2.1 避免全表扫描​2.2 使用覆盖索引​2.3 合理使用 JOIN​ 三、索引优化​3.1 索引设计原则​3.2 索引维护​ 在数据驱动的当今时代&#xff0c;MySQL 作为应用广泛的开源关系型数据库&…...

谈谈对spring IOC的理解,原理和实现

一、IoC 核心概念 1. 控制反转&#xff08;Inversion of Control&#xff09; 传统编程中对象自行管理依赖&#xff08;主动创建&#xff09;&#xff0c;而IoC将控制权转移给容器&#xff0c;由容器负责对象的创建、装配和管理&#xff0c;实现依赖关系的反向控制。 2. 依赖…...

Element UI实现表格全选、半选

制作如图所示的表格全选、半选&#xff1a; 父组件 <template><div id"app"><SelectHost :hostArray"hostArray" /></div> </template><script> import SelectHost from ./components/SelectHost.vue export default…...

Dify实现自然语言生成SQL并执行

目录 一、需求分析 二、解决思路 问题1&#xff1a;文字描述生成SQL语句 问题2&#xff1a;执行生成的SQL语句 完整解决方案 三、最终效果展示 四、具体实现 1.Agent提示词 2.知识库数据 3.sql执行器工作流创建 3.1 节点1 3.2 节点2 3.3 节点3 3.4 最终配置界面预…...

【leetcode hot 100 347】前 K 个高频元素

解法一&#xff1a;用map的value记录key出现的次数&#xff0c;用PriorityQueue构造最小堆。 class Solution {public int[] topKFrequent(int[] nums, int k) {// 把元素放在map中Map<Integer,Integer> map new HashMap<>();for(int num:nums){if(map.containsK…...

golang不使用锁的情况下,对slice执行并发写操作,是否会有并发问题呢?

背景 并发问题最简单的解决方案加个锁,但是,加锁就会有资源争用,提高并发能力其中的一个优化方向就是减少锁的使用。 我在之前的这篇文章《开启多个协程,并行对struct中的每个元素操作,是否会引起并发问题?》中讨论过多协程场景下struct的并发问题。 Go语言中的slice在…...

一文了解Gradle 依赖管理(五)- 依赖管理缓存依赖

文章目录 1. 版本目录 (Version Catalogs)1. 版本目录的概念与优势2. 主要优势3. 基本配置4. 使用版本目录5.使用外部版本目录文件6.实际项目中的版本目录最佳实践 2. 依赖锁定&#xff08;Dependency Locking&#xff09;1. 依赖锁定的概念与重要性2. 主要优势3. 如何启用依赖…...

如何在 Postman 中发送 PUT 请求?

在 Postman 中发送 PUT 请求的步骤相对简单&#xff0c;包括新建接口、选择 PUT 方法、填写 URL 和参数等几个主要步骤。 Postman 发送 put 请求教程...

Ubuntu20.04.6系统根目录扩容

文章目录 方法一&#xff1a;**1. 检查磁盘和分区情况****2. 扩展 vda3 分区****3. 扩展 LVM 物理卷****4. 扩展 LVM 逻辑卷****5. 扩展文件系统** 方法二:1. 查看当前磁盘分区情况2. 创建新分区3. 重新加载分区表4. 扩展物理卷&#xff08;PV&#xff09;5. 扩展逻辑卷&#x…...

《AI赋能SQL Server,数据处理“狂飙”之路》

在数字化浪潮汹涌的当下&#xff0c;企业的数据量犹如滚雪球般飞速增长。据统计&#xff0c;过去几年全球数据量的年增长率高达30%以上 &#xff0c;海量数据如同双刃剑&#xff0c;既蕴含着无限商机&#xff0c;也给数据处理带来巨大挑战。SQL Server作为一款强大的关系型数据…...

c++ 日志框架G3log介绍及在嵌入式Linux上的移植(交叉编译)

在开发高性能的C应用程序时&#xff0c;一个高效的日志框架是不可或缺的。G3log是一个开源的日志库&#xff0c;以其高性能和易于使用著称&#xff0c;特别适用于嵌入式Linux环境。本文将详细介绍G3log的主要特性和如何在嵌入式Linux平台上进行交叉编译。 G3log介绍 G3log 是一…...

Buffer overFolw---Kryo序列化出现缓冲区溢出的问题解决

问题&#xff1a; 由于我的数据量太大&#xff0c;我设置批次为10000万&#xff0c;50w数据大概有400M左右&#xff0c;然后进行spark数据处理时候报错为org.apache.spark.SparkException:Kryo serialization failed:Buffer overFolw.Available:0,rquired 58900977,To …...

leetcode日常刷题

题目&#xff1a;K个一组翻转链表 思路 题目要求k个一组进行反转&#xff0c;首先考虑到如果k为1&#xff0c;那就可以直接返回链表头&#xff0c;这种情况没必要翻转。 如果只有一个节点或者head为空结点&#xff0c;直接返回head即可&#xff08;一个节点翻转k次都是本身&am…...

菜鸡前端计算机强基计划之CS50 第七课 python 入门—— Python 中yield专题学习

菜鸡前端计算机强基计划之CS50 第七课 python 入门—— Python 中yield专题学习 1. 什么是 yield&#xff1f;直观感受 2. 生成器是什么&#xff1f;一个简单的例子 3. yield 的工作原理&#xff08;图形化解释&#xff09;4. yield 和内存的魔法用列表返回所有值用生成器逐步生…...

密码学——知识问答

目录 1、阐述公开密钥算法的定义&#xff0c;结合RSA算法说明公钥密码的基本要求。 说明公钥与私钥两种密码学并举例与其应用 1. 公钥密码学&#xff08;非对称加密&#xff09;&#xff1a; 2. 私钥密码学&#xff08;对称加密&#xff09;&#xff1a; 对比公钥与私钥密码…...

Talos-docker版本中创建 Kubernetes 集群

在talos容器化版本中部署Kubernetes集群&#xff0c;用于折腾学习。 1.系统信息 虚拟机软件&#xff1a;VMware Worktation 虚拟机配置&#xff1a;4G内存 4vCPU 200GB磁盘 操作系统&#xff1a;CentOS7.9 docker&#xff1a;20.10.15 PS&#xff1a;为啥VMware Worktat…...

【Excel使用技巧】某列保留固定字段或内容

目录 ✅ 方法一&#xff1a;使用 Excel 公式提取 body 部分 &#x1f50d; 解释&#xff1a; ✅ 方法二&#xff1a;批量处理整列数据 &#x1f6a8; 注意事项 &#x1f6a8; 处理效果 我想保留Excel某一列的固定内容&#xff0c;比如原内容是&#xff1a; thread entry i…...

matlab 模拟 闪烁体探测器全能峰

clc;clear;close all %% 参数设置 num_events 1e5; % 模拟事件数 E 662e3; % γ射线能量&#xff08;eV&#xff09; Y 38000; % 光产额&#xff08;photon/MeV&#xff0c;NaI(Tl)&#xff09; eta 0.2; % 量子效率 G 1e6; …...

【leetcode hot 100 74】搜索二维矩阵

解法一&#xff1a;双重二分查找 class Solution {public boolean searchMatrix(int[][] matrix, int target) {int nmatrix.length, mmatrix[0].length;int row10, row2n-1, col10, col2m-1;int row_mid, col_mid;while(row1<row2){row_mid (row1row2)/2;while(col1<c…...

Maven 中 maven.test.skip 与skipTests 区别

在 Maven 中&#xff0c;maven.test.skip 和 skipTests 都用于控制测试的跳过行为&#xff0c;但它们的作用范围和底层机制有显著区别。以下是详细对比&#xff1a; 1. maven.test.skip 定义 maven.test.skip 是一个用户自定义属性&#xff08;需在 pom.xml 的 <propertie…...

LLM - R1 强化学习 DRPO 策略优化 DAPO 与 Dr. GRPO 算法 教程

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/146533892 在强化学习算法中&#xff0c;DAPO (Decoupled Clip and Dynamic Sampling Policy Optimization)&#xff0c;通过解耦裁剪和动态采样策…...

element-plus中,Loading 加载组件的使用

一.基本使用 给一个组件&#xff0c;如&#xff1a;table表格&#xff0c;加上v-loading"true"即可。 举例&#xff1a;复制如下代码。 <template><el-table v-loading"loading" :data"tableData" style"width: 100%"><…...

部署完dify:localhost/install 页面不停转圈圈,报错CROS error

解决办法 docker/.env 文件中&#xff0c;需要配置如下&#xff1a; NGINX_HTTPS_ENABLEDtrue NGINX_ENABLE_CERTBOT_CHALLENGEtrue 把Nginx的跨域请求打开...

UE4学习笔记 FPS游戏制作17 让机器人持枪 销毁机器人时也销毁机器人的枪 让机器人射击

添加武器插槽 打开机器人的Idle动画&#xff0c;方便查看武器位置 在动画面板里打开骨骼树&#xff0c;找到右手的武器节点&#xff0c;右键添加一个插槽&#xff0c;重命名为RightWeapon&#xff0c;右键插槽&#xff0c;添加一个预览资产&#xff0c;选择Rifle&#xff0c;根…...

【网络丢包】原因排查及优化

在流式响应中&#xff0c;丢包现象可能由多种因素引起&#xff0c;详细的原因分析、排查方法及优化策略&#xff1a; 一、丢包原因分析 网络拥塞 当网络带宽不足或流量突增时&#xff0c;路由器/交换机可能丢弃超出处理能力的数据包。 硬件问题 网卡、路由器、交换机等设备故…...

Spring Boot 实战:MD5 密码加密应用全解析

Spring Boot 实战&#xff1a;MD5 密码加密应用全解析 1. 引言 在应用开发中&#xff0c;密码安全是用户隐私保护的核心环节。直接存储明文密码存在极大的安全风险&#xff08;如数据库泄露导致用户信息被盗&#xff09;。MD5 加密作为一种广泛使用的哈希算法&#xff0c;可将…...

Android 底部EditView输入时悬浮到软键盘上方

1. 修改 Activity 的 Manifest 配置 确保你的 Activity 在 AndroidManifest.xml 中有以下配置&#xff1a; <activityandroid:name".YourActivity"android:windowSoftInputMode"adjustResize|stateHidden" /> 关键点&#xff1a; adjustResize 是…...

【deepseek 学c++】weakptr引用场景

std::weak_ptr 是 C 中与 std::shared_ptr 配合使用的智能指针&#xff0c;它本身不拥有资源的所有权&#xff0c;仅观察资源的状态&#xff0c;主要用于解决 shared_ptr 的循环引用问题和临时访问共享资源的需求。以下是 weak_ptr 的典型应用场景和核心价值&#xff1a;![ 为…...

从技术架构和生态考虑,不是单纯的配置优化,还有哪些方式可以提高spark的计算性能

从技术架构和生态系统层面提升Spark的计算性能&#xff0c;可采取以下核心策略&#xff1a; 一、计算模型重构与执行引擎升级 1. 弹性分布式数据集&#xff08;RDD&#xff09;的血统优化 通过RDD的Lineage&#xff08;血统&#xff09;机制实现容错时&#xff0c;采用增量式…...

怎样进行服务器的日常安全监控和审计?

服务器的日常安全监控和审计是保障服务器安全运行的重要措施&#xff0c;以下是一些常见的方法和工具&#xff1a; 系统日志监控 启用日志功能&#xff1a;确保服务器操作系统、应用程序和数据库等都启用了详细的日志记录功能。例如&#xff0c;Linux 系统中的 syslog&#x…...

Java 集合框架面经

1、说说有哪些常见的集合框架&#xff1f; 集合框架可以分为两条大的支线&#xff1a; Map 接口&#xff1a;表示键值对的集合&#xff0c;一个键映射到一个值。键不能重复&#xff0c;每个键只能对应一个值。Map 接口的实现类包括 HashMap、LinkedHashMap、TreeMap 等。Colle…...

【已解决】Git:为什么 .gitignore 不生效?如何停止跟踪已提交文件并阻止推送?

你可能遇到的问题 你已经提交了某个文件夹&#xff08;如 dataset&#xff09;到 Git 仓库&#xff0c;之后修改了它&#xff0c;但发现修改内容被 Git 持续跟踪&#xff0c;无法通过 .gitignore 忽略。尝试在 .gitignore 中添加规则后&#xff0c;修改的文件仍然显示为"…...

MOSN(Modular Open Smart Network)-04-TLS 安全链路

前言 大家好&#xff0c;我是老马。 sofastack 其实出来很久了&#xff0c;第一次应该是在 2022 年左右开始关注&#xff0c;但是一直没有深入研究。 最近想学习一下 SOFA 对于生态的设计和思考。 sofaboot 系列 SOFAStack-00-sofa 技术栈概览 MOSN&#xff08;Modular O…...

SICAR 标准 KUKA 机器人标准功能块说明手册

功能块名称:LSicar_Robot_KUKA_PrD 目录 1. 概述 2. 功能说明 2.1 程序控制 2.2 状态监控 2.3 报警与故障处理 2.4 驱动控制 3. 关键参数说明 4. 操作步骤指南 4.1 初始化配置 4.2 运行控制 4.3 状态监控 5. 常见故障处理 6. 注意事项 附录1:程序段索引 附录…...

QT三 自定义控件,自定义控件的事件处理自定义事件过滤,原始事件过滤

一 自定义控件 现在的需求是这样&#xff1a; 假设我们要在QWidget 上做定制&#xff0c;这个定制包括了关于 一些事件处理&#xff0c;意味着要重写QWidget的一些代码&#xff0c;这是不实际的&#xff0c;因此我们需要自己写一个MyWidget继承QWidget&#xff0c;然后再MyWi…...

Leetcode算法方法总结

1. 双指针法解决链表/数组题目 只要数组有序&#xff0c;就要想到双指针做法。还有二分法 回文串一般也会用到双指针&#xff0c;回文串的长度由于可能是奇数也可能是偶数&#xff0c;所以在寻找时&#xff0c;既需要寻找奇数长度的回文串&#xff0c;也需要寻找偶数长度的回文…...

【Elasticsearch基础】基本核心概念介绍

Elasticsearch作为当前最流行的分布式搜索和分析引擎&#xff0c;其强大的功能背后是一套精心设计的核心概念体系。本文将深入解析Elasticsearch的五大核心概念&#xff0c;帮助开发者构建坚实的技术基础&#xff0c;并为高效使用ES提供理论支撑。 1 索引&#xff08;Index&…...

docker远程debug

1. 修改 Java 启动命令 在 Docker 容器中启动 Java 程序时&#xff0c;需要添加 JVM 调试参数&#xff0c;jdk8以上版本 java -agentlib:jdwptransportdt_socket,servery,suspendn,address*:5005 -jar your-app.jar jdk8及以下版本&#xff1a; java -Xdebug -Xrunjdwp:tra…...

华为eNSP-配置静态路由与静态路由备份

一、静态路由介绍 静态路由是指用户或网络管理员手工配置的路由信息。当网络拓扑结构或者链路状态发生改变时&#xff0c;需要网络管理人员手工修改静态路由信息。相比于动态路由协议&#xff0c;静态路由无需频繁地交换各自的路由表&#xff0c;配置简单&#xff0c;比较适合…...

CentOS 7下安装PostgreSQL 15

一、简介 PostgreSQL是一种特性非常齐全的自由软件的对象-关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;是以加州大学计算机系开发的POSTGRES&#xff0c;4.2版本为基础的对象关系型数据库管理系统。POSTGRES的许多领先概念只是在比较迟的时候才出现在商业…...

时序数据库 InfluxDB(一)

时序数据库 InfluxDB&#xff08;一&#xff09; 数据库种类有很多&#xff0c;比如传统的关系型数据库 RDBMS&#xff08; 如 MySQL &#xff09;&#xff0c;NoSQL 数据库&#xff08; 如 MongoDB &#xff09;&#xff0c;Key-Value 类型&#xff08; 如 redis &#xff09…...

动态添加view方法-微信小程序

在微信小程序中&#xff0c;通过动态数据绑定和条件渲染来实现动态添加 view 组件的效果。 以下是一个简单的示例&#xff0c;展示如何根据数据动态添加 view。 WXML 文件 在 WXML 文件中&#xff0c;使用 wx:for 指令来遍历数组&#xff0c;并动态生成 view 组件。 <view…...

Java中清空集合列表元素有哪些方式

在 Java 里&#xff0c;存在多种清空列表的方式&#xff0c;下面为你汇总并附上对应的示例代码&#xff1a; import java.util.ArrayList; import java.util.List;public class ListClearDemo {public static void main(String[] args) {// 初始化一个列表List<String> …...

QOpenGLWidget动态加载功能实现教程(Qt+OpenGL)

QOpenGLWidget动态加载功能实现教程 我需要在Qt里面使用QOpenGLWidget显示OpenGL窗口&#xff0c;并且需要实现加载模型后重新渲染更新窗口的功能&#xff0c;但是一直无法更新被卡住了&#xff0c;现在把问题解决了总结一下整个实现过程。 创建一个自己的OpenGLWidget类 QOp…...

00.【Linux系统编程】 Linux初识(云服务器设置CentOS并使用、Xshell链接云服务器)

目录 一、华为云服务器免费体验申请 二、Xshell远程链接创建好的华为云服务器 2.1 下载Xshell 2.2 Xshell远程连接华为云服务器 一、华为云服务器免费体验申请 华为云官网 1. 进入华为云官网&#xff0c;最上面一栏点活动&#xff0c;并进入免费体验中心。 2. 找到含有“…...

数据结构-二叉链表存储的二叉树

树形结构是一类重要的非线性数据结构&#xff0c;其中以树和二叉树最为常用。对于每一个结点至多只有两课子树的一类树&#xff0c;称其为二叉树。二叉树的链式存储结构是一类重要的数据结构&#xff0c;其形式定义如下&#xff1a; 而二叉树的前序、中序遍历是非常重要的能够访…...