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

【网络编程】事件选择模型

十、基于I/O模型的网络开发

10.9 事件选择模型

10.0.1 基本概念

事件选择(WSAEventSelect) 模型是另一个有用的异步 I/O 模型。和 WSAAsyncSelect 模 型类似的是,它也允许应用程序在一个或多个套接字上接收以事件为基础的网络事件通知,最 主要的差别在于网络事件会投递至一个事件对象句柄,而非投递到一个窗口例程。

10.9.2 WSAEventSelect函数

WSAEventSelect 模型主要由函数WSAEventSelect 来实现。注意,这里用了“主要由”, 说明还有其他配套函数一起辅助来实现这个模型。

后面会讲到其他函数。这里先看一下 WSAEventSelect。

WSAEventSelect 函数将一个已经创建好的事件对象(由WSACreateEvent 创建)与某个套 接字关联在一起,同时注册自己感兴趣的网络事件类型。WSAEventSelect 的函数声明如下:

int WSAAPI WSAEventSelect(SOCKET S,WSAEVENT hEventObject, long lNetworkEvents);
  • 其中,s 是套接字描述符;

  • hEventObject标识要与指定的网络事件集关联的事件对象的句 柄 ;

  • INetworkEvents指定应用程序感兴趣的网络事件组合的位掩码。

  • 如果函数成功,那么返回值为零;否则,将返回值SOCKET_ERROR, 并且可以通过调用 WSAGetLastError来获取特定的错误号。

  • 与select 和 WSAAsyncSelect 函数一样,WSAEventSelect 通常用于确定何时可以进行数据 收发操作(确定调用send或 recv能立即成功的时间点)。如果时间点没到,那么函数会返回 WSAEWOULDBLOCK, 此时我们要正确处理这个错误码。

10.9.3 实 战WSAEventSelect模型

事件选择模型的基本思路是:为感兴趣的一组网络事件创建一个事件对象,再调用 WSAEventSelect 函数将网络事件和事件对象关联起来。当网络事件发生时,Winsock 会使相 应的事件对象收到通知,在事件对象上等待的函数就会返回。之后,再调用 WSAEnumNetworkEvents函数便可获取发生了什么网络事件。
事件选择模型写的TCP 服务器实现的过程如下:

  • (1)创建事件对象和套接字。创建一个事件对象的方法是调用 WSACreateEvent 函数, 它的定义如下:
WSAEVENT WSAAPI WSACreateEvent();
  • 如果没有发生错误,那么函数将返回事件对象的句柄;

  • 否则,返回值为 WSA_INVALID_EVENT, 可以通过WSAGetLastError 函数获取更多的错误信息。这个事件对 象创建后,其初始状态为“未受信”,就是没有收到通知状态。

  • WSACreateEvent 创建的事件有两种工作状态以及两种工作模式:工作状态分别是“有信 号 " (signaled) 和“无信号" (nonsignaled), 工作模式包括“人工重设” (manual reset) 和“自动重设” (auto reset) 。WSACreateEvent 创建的事件开始是处于一种无信号的工作状 态,并用一种人工重设模式来创建事件句柄。

  • (2)将事件对象与套接字关联在一起,同时注册自己感兴趣的网络事件类型(FD_READ、 FD_WRITE、FD_ACCEPT、FD_CONNECT、FD_CLOSE 等),这个过程通过函数 WSAEventSelect实现。

  • (3)调用事件等待函数WSAWaitForMultipleEvents在所有事件对象上等待,该函数返回后,我们就可以确认在哪些套接字上发生了网络事件。 当一个或所有指定的事件对象处于信号状态、超时或执行了 I/O 完成例程时,函数 WSAWaitForMultipleEvents返回,该函数声明如下:

#include <winsock2.h>
#pragma comment(lib, "Ws232.lib")
DWORD WSAAPI WSAWaitForMultipleEvents(DWORD CEvents,const WSAEVENT *lphEvents, BOOL fWaitAll,DWORD dwTimeout,BOOL fAlertable);
  • cEvents: 表 示lphEvent 所指数组中的事件对象句柄数,事件对象句柄的最大数量是 WSA_MAXIMUM_WAIT_EVENTS, 必须指定一个或多个事件。
  • lphEvents: 指向事件对象句柄数组的指针,数组可以包含不同类型对象的句柄,如果 后面参数fWaitAll 设置为TRUE, 那么它不能包含同一句柄的多个副本,如果在等待 仍处于挂起状态时关闭其中一个句柄,那么WSAWaitForMultipleEvents 的行为将不 可知。另外,句柄必须具有同步访问权限。
  • fWaitAll: 输入参数,用于指定等待类型的值。如果赋值为TRUE, 那么当lphEvents 数组中所有对象的状态都处于有信号时,函数将返回。注意,是所有对象都处于信号 状态才返回。如果赋值为FALSE, 则当向任一事件对象发出信号时,函数返回。在 这一种情况下,返回值减去WSA_WAIT_EVENT_0 表示其状态导致函数返回的事件 对象的索引。如果在调用期间有多个事件对象发出信号,那么返回值指示信号事件对 象的lphEvents 数组索引的最小值。
  • dwTimeout: 超时时间,单位是毫秒。如果超时时间到,则函数返回,即使不满足 fWaitAll 参数指定的条件。如果 dw Timeout参数为零,则函数将测试指定事件对象的 状态并立即返回。如果dwTimeout 是 WSA_INFINITE, 则函数将永远等待。
  • fAlertable: 指定线程是否处于可警报的等待状态,以便系统可以执行I/O 完成例程。 如果为TRUE, 则线程将处于可警报的等待状态,并且当系统执行I/O 完成例程时, 函数可以返回。在这种情况下,将返回 WSA_WAIT_IO_COMPLETION, 并且尚未 发出正在等待的事件的信号。应用程序必须再次调用WSAWaitForMultipleEvents 函 数。如果为FALSE, 则线程不会处于可警报的等待状态,也不会执行I/O 完成例程。

如果函数成功,那么返回值为以下值之一:

  • WSA_WAIT_EVEN_0 到 (WSA_WAIT_EVENT_0+cEvents-1): 如果参数 fWaitAll 参数为 TRUE, 则返回值指示已向所有指定的事件对象发出信号。如果 fWaitAll 参数为FALSE, 则返回值减去WSA_WAIT_EVENT_0 表示其状态导致函数 返回的事件对象的索引。如果在调用期间有多个事件对象发出信号,则返回值指示信 号事件对象的lphEvents 数组索引的最小值。
  • WSA_WAIT_IO_COMPLETION:等待被执行的一个或多个I/O 完成例程结束。正在 等待的事件尚未发出信号,应用程序必须再次调用WSAWaitForMultipleEvents 函数。 只有fAlertable 参数为TRUE 时,才能返回此返回值。
  • WSA_WAIT_TIMEOUT: 超时间隔已过,并且未满足fWaitAll参数指定的条件,未
    执行任何I/O完成例程。

如果函数失败,则返回值为WSA_WAIT_FAILED。此时可以通过函数WSAGetLastError 获取更多错误码,常见错误码如下:

  • WSANOTINITIALISED: 在调用本API 之前应成功调用WSAStartup()。

  • WSAENETDOWN: 网络子系统失效。

  • WSA_NOT_ENOUGH_MEMORY: 无足够内存完成该操作。

  • WSA_INVALID_HANDLE:lphEvents 数组中的一个或多个值不是合法的事件对象句柄。

  • WSA_INVALID_PARAMETER:cEvents参数未包含合法的句柄数目。

  • (4)检测所指定套接字上发生网络事件,然后处理发生的网络事件,完毕继续在事件对 象上等待。检测所指定套接字上发生网络事件是通过函数WSAEnumNetworkEvents 来实现, 该函数声明如下:

#include <winsock2.h>
#pragma comment(lib, "Ws232.lib")int WSAAPI WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents);
  • s: 套接字描述符。
  • hEventObject: 标识要重置的关联事件对象的可选句柄。
  • lpNetworkEvents: 指 向WSANETWORKEVENTS 结构的指针,该结构由发生的网络 事件和任何相关错误代码的记录填充。

如果操作成功,函数返回值为零;否则,将返回值SOCKET ERROR, 并且可以通过调用WSAGetLastError来获取特定的错误码。

以上4步是使用事件选择模型的基本步骤。下面我们看一个实例。

服务端

#define _WINSOCK_DEPRECATED_NO_WARNINGS#include <winsock2.h>
#include <Windows.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")using std::cout;
using std::cin;
using std::endl;
using std::ends;void WSAEventServerSocket()
{SOCKET server = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (server == INVALID_SOCKET) {cout << "创建SOCKET失败!,错误代码:" << WSAGetLastError() << endl;return;}int error = 0;sockaddr_in addr_in;addr_in.sin_family = AF_INET;addr_in.sin_port = htons(6000);addr_in.sin_addr.s_addr = INADDR_ANY;error = ::bind(server, (sockaddr*)&addr_in, sizeof(sockaddr_in));if (error == SOCKET_ERROR) {cout << "绑定端口失败!,错误代码:" << WSAGetLastError() << endl;return;}listen(server, 5);if (error == SOCKET_ERROR) {cout << "监听失败!,错误代码:" << WSAGetLastError() << endl;return;}cout << "成功监听端口 :" << ntohs(addr_in.sin_port) << endl;WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];        // 事件对象数组SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];            // 事件对象数组对应的SOCKET句柄int nEvent = 0;                    // 事件对象数组的数量 WSAEVENT event0 = ::WSACreateEvent();::WSAEventSelect(server, event0, FD_ACCEPT | FD_CLOSE);eventArray[nEvent] = event0;sockArray[nEvent] = server;nEvent++;while (true) {int nIndex = ::WSAWaitForMultipleEvents(nEvent, eventArray, false, WSA_INFINITE, false);if (nIndex == WSA_WAIT_IO_COMPLETION || nIndex == WSA_WAIT_TIMEOUT) {cout << "等待时发生错误!错误代码:" << WSAGetLastError() << endl;break;}nIndex = nIndex - WSA_WAIT_EVENT_0;WSANETWORKEVENTS event;SOCKET sock = sockArray[nIndex];::WSAEnumNetworkEvents(sock, eventArray[nIndex], &event);if (event.lNetworkEvents & FD_ACCEPT) {if (event.iErrorCode[FD_ACCEPT_BIT] == 0) {if (nEvent >= WSA_MAXIMUM_WAIT_EVENTS) {cout << "事件对象太多,拒绝连接" << endl;continue;}sockaddr_in addr;int len = sizeof(sockaddr_in);SOCKET client = ::accept(sock, (sockaddr*)&addr, &len);if (client != INVALID_SOCKET) {cout << "接受了一个客户端连接 " << inet_ntoa(addr.sin_addr) << ":" << ntohs(addr.sin_port) << endl;WSAEVENT eventNew = ::WSACreateEvent();::WSAEventSelect(client, eventNew, FD_READ | FD_CLOSE | FD_WRITE);eventArray[nEvent] = eventNew;sockArray[nEvent] = client;nEvent++;}}}else if (event.lNetworkEvents & FD_READ) {if (event.iErrorCode[FD_READ_BIT] == 0) {char buf[2500];ZeroMemory(buf, 2500);int nRecv = ::recv(sock, buf, 2500, 0);if (nRecv > 0) {cout << "收到一个消息 :" << buf << endl;char strSend[] = "hi,client,I am server, I recvived your message.";::send(sock, strSend, strlen(strSend), 0);}}}else if (event.lNetworkEvents & FD_CLOSE) {::WSACloseEvent(eventArray[nIndex]);::closesocket(sockArray[nIndex]);cout << "一个客户端连接已经断开了连接" << endl;for (int j = nIndex; j < nEvent - 1; j++) {eventArray[j] = eventArray[j + 1];sockArray[j] = sockArray[j + 1];}nEvent--;}else if (event.lNetworkEvents & FD_WRITE) {cout << "一个客户端连接允许写入数据" << endl;}} // end while::closesocket(server);
}int main(){WSADATA wsaData;int error;WORD wVersionRequested;wVersionRequested = WINSOCK_VERSION;error = WSAStartup(wVersionRequested, &wsaData);if (error != 0) {WSACleanup();return 0;}WSAEventServerSocket();WSACleanup();return 0;
}

客户端

#define _WINSOCK_DEPRECATED_NO_WARNINGS#include<stdlib.h>
#include<WINSOCK2.H>
#include <windows.h> 
#include <process.h>  #include<iostream>
#include<string>using namespace std;#define BUF_SIZE 64
#pragma comment(lib,"WS2_32.lib")void recv(PVOID pt)
{SOCKET  sHost = *((SOCKET*)pt);while (true){char buf[BUF_SIZE];//清空接收数据的缓冲区memset(buf, 0, BUF_SIZE);int retVal = recv(sHost, buf, sizeof(buf), 0);if (SOCKET_ERROR == retVal){int  err = WSAGetLastError();//无法立即完成非阻塞Socket上的操作if (err == WSAEWOULDBLOCK){Sleep(1000);//printf("\nwaiting  reply!");continue;}else if (err == WSAETIMEDOUT || err == WSAENETDOWN || err == WSAECONNRESET)//已建立连接{printf("recv failed!");closesocket(sHost);WSACleanup();return;}}Sleep(100);printf("\n%s", buf);//break;}
}int main()
{WSADATA wsd;SOCKET sHost;SOCKADDR_IN servAddr;//服务器地址int retVal;//调用Socket函数的返回值char buf[BUF_SIZE];//初始化Socket环境if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){printf("WSAStartup failed!\n");return -1;}sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//设置服务器Socket地址servAddr.sin_family = AF_INET;servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//在实际应用中,建议将服务器的IP地址和端口号保存在配置文件中servAddr.sin_port = htons(6000);//计算地址的长度int sServerAddlen = sizeof(servAddr);//调用ioctlsocket()将其设置为非阻塞模式int iMode = 1;retVal = ioctlsocket(sHost, FIONBIO, (u_long FAR*) & iMode);if (retVal == SOCKET_ERROR){printf("ioctlsocket failed!");WSACleanup();return -1;}//循环等待while (true){//连接到服务器retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr));if (SOCKET_ERROR == retVal){int err = WSAGetLastError();//无法立即完成非阻塞Socket上的操作if (err == WSAEWOULDBLOCK || err == WSAEINVAL){Sleep(1);printf("check  connect!\n");continue;}else if (err == WSAEISCONN)//已建立连接{break;}else{printf("connection failed!\n");closesocket(sHost);WSACleanup();return -1;}}}unsigned long threadId = _beginthread(recv, 0, &sHost);//启动一个线程接收数据的线程   while (true){//向服务器发送字符串,并显示反馈信息printf("input a string to send:\n");std::string str;//接收输入的数据std::cin >> str;//将用户输入的数据复制到buf中ZeroMemory(buf, BUF_SIZE);strcpy_s(buf, str.c_str());if (strcmp(buf, "quit") == 0){printf("quit!\n");break;}while (true){retVal = send(sHost, buf, strlen(buf), 0);if (SOCKET_ERROR == retVal){int err = WSAGetLastError();if (err == WSAEWOULDBLOCK){//无法立即完成非阻塞Socket上的操作Sleep(5);continue;}else{printf("send failed!\n");closesocket(sHost);WSACleanup();return -1;}}break;}}return 0;
}

参考书籍《Visual C++2017 网络编程实战》

相关文章:

【网络编程】事件选择模型

十、基于I/O模型的网络开发 10.9 事件选择模型 10.0.1 基本概念 事件选择(WSAEventSelect) 模型是另一个有用的异步 I/O 模型。和 WSAAsyncSelect 模 型类似的是&#xff0c;它也允许应用程序在一个或多个套接字上接收以事件为基础的网络事件通知&#xff0c;最 主要的差别在…...

网易邮箱如何用大数据任务调度实现海量邮件数据处理?Apache DolphinScheduler用户交流会上来揭秘!

你是否对大数据领域的前沿应用充满好奇&#xff1f;网易邮箱作为互联网大厂网易的重要业务线&#xff0c;在大数据应用方面有着诸多值得借鉴的实践经验。你是否渴望深入了解网易邮箱如何借助 Apache DolphinScheduler 实现海量邮件数据处理、用户行为分析、实时监控等核心业务场…...

前端知识点---路由模式-实例模式和单例模式(ts)

在 ArkTS&#xff08;Ark UI 框架&#xff09;中&#xff0c;路由实例模式&#xff08;Standard Instance Mode&#xff09;主要用于管理页面跳转。当创建一个新页面时&#xff0c;可以选择标准实例模式&#xff08;Standard Mode&#xff09;或单实例模式&#xff08;Single M…...

固定表头、首列 —— uniapp、vue 项目

项目实地&#xff1a;也可以在 【微信小程序】搜索体验&#xff1a;xny.handbook 另一个体验项目&#xff1a;官网 一、效果展示 二、代码展示 &#xff08;1&#xff09;html 部分 <view class"table"><view class"tr"><view class&quo…...

langchain系列(九)- LangGraph 子图详解

目录 一、导读 二、原理说明 1、简介 2、子图图示 3、使用说明 三、基础代码实现 1、实现功能 2、Graph 图示 3、代码实现 4、输出 5、分析 四、人机交互 1、实现中断 2、历史状态&#xff08;父图&#xff09; 3、历史状态&#xff08;子图&#xff09; 4、历史…...

搜索引擎是如何理解你的查询并提供精准结果的?

目录 一、搜索引擎简单介绍 二、搜索引擎整体架构和工作过程 &#xff08;一&#xff09;整体分析 &#xff08;二&#xff09;爬虫系统 三个基本点 爬虫系统的工作流程 关键考虑因素和挑战 &#xff08;三&#xff09;索引系统 网页处理阶段 预处理阶段 反作弊分析…...

【前端】【组件】【vue2】封装一个vue2的ECharts组件,不用借助vue-echarts

在Vue2项目中使用ECharts 5.6的完整实现步骤如下&#xff1a; 安装依赖 npm install echarts5.6.2 --save # 指定安装5.x最新版本基础组件实现&#xff08;新建components/ECharts.vue&#xff09; <template><div ref"chartDom" class"echarts-co…...

18天 - 常见的 HTTP 状态码有哪些?HTTP 请求包含哪些内容,请求头和请求体有哪些类型?HTTP 中 GET 和 POST 的区别是什么?

常见的 HTTP 状态码有哪些&#xff1f; HTTP 状态码用于指示服务器对客户端请求的响应结果&#xff0c;常见的 HTTP 状态码可以分为以下几类&#xff1a; 1. 信息类&#xff08;1xx&#xff09; 100 Continue&#xff1a;客户端应继续发送请求。101 Switching Protocols&…...

IDEA软件安装环境配置中文插件

一、Java环境配置 1. JDK安装8 访问Oracle官网下载JDK8&#xff08;推荐JDK8&#xff0c;11&#xff09;Java Downloads | Oracle 双击安装程序&#xff0c;保持默认设置连续点击"下一步"完成安装 验证JDK安装&#xff0c;winR键 然后输入cmd&#xff0c;输入java…...

循环神经网络(RNN):时序建模的核心引擎与演进之路

在人工智能处理序列数据的战场上&#xff0c;循环神经网络&#xff08;RNN&#xff09;如同一个能够理解时间的智者。从 2015 年谷歌神经机器翻译系统颠覆传统方法&#xff0c;到 2023 年 ChatGPT 实现对话连续性&#xff0c;这些突破都植根于 RNN 对时序建模的深刻理解。本文将…...

HTML 表单 (form) 的作用解释

表单在网页中主要负责的是数据采集功能&#xff0c;一个表单基本由三部分组成&#xff1a; 表单标签&#xff1a;这里面包含了处理表单数据所用 CGI &#xff08;Common Gateway Interface&#xff0c;通用网关接口&#xff09;程序的 URL &#xff08;Uniform Resource Locati…...

Windows控制台函数:控制台读取输入函数ReadConsoleA()

目录 什么是 ReadConsoleA&#xff1f; 它长什么样&#xff1f; 怎么用它&#xff1f; 它跟 std::cin 有什么不一样&#xff1f; 注意事项 什么是 ReadConsoleA&#xff1f; ReadConsoleA 是一个 Windows API 函数&#xff0c;用来从控制台读取用户输入。想象一下&#…...

网络tcp协议设置,网络tcp协议设置不了

网络TCP协议的设置通常涉及到多个方面&#xff0c;包括IP地址、子网掩码、默认网关、DNS服务器等参数的配置&#xff0c;以及TCP/IP协议栈本身的配置。如果遇到网络TCP协议设置不了的问题&#xff0c;可能是由多种原因导致的。以下是一些可能的原因及解决方法&#xff1a; 一、…...

电脑总显示串口正在被占用处理方法

1.现象 在嵌入式开发过程中&#xff0c;有很多情况下要使用串口调试&#xff0c;其中485/422/232转usb串口是非常常见的做法。 根据协议&#xff0c;接口芯片不同&#xff0c;需要安装对应的驱动程序&#xff0c;比如ch340&#xff0c;cp2102&#xff0c;CDM212364等驱动。可…...

R语言和RStudio安装

整体还是比较简单的&#xff0c;主要是记录个流程。 官方镜像站列表R语言官网 1 安装R&#xff08;2025/3/6&#xff09; R语言官网&#xff1a;The R Project for Statistical Computing 打开之后就Hello world一下吧 配置环境变量 2 安装RStudio 下载地址&#xff1a;htt…...

RHEL/CentOS 7.9使用firewalld限制出方向策略

背景 通常使用firewalld时候多为限制入方向访问&#xff0c;本次因有系统需要在生产环境部署测试环境&#xff0c;需求人希望在该测试环境中限制访问的对象&#xff0c;避免对生产造成影响 基础团队小伙伴参照rich-files&#xff0c;通过CLI&#xff0c;GUI反复进行进行配置验…...

设计模式之建造者模式:原理、实现与应用

引言 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它通过将复杂对象的构建过程分解为多个简单的步骤&#xff0c;使得对象的创建更加灵活和可维护。建造者模式特别适用于构建具有多个组成部分的复杂对象。本文将深入探讨建造者模式的原…...

1688店铺所有商品数据接口详解

​​一、接口概述淘宝开放平台提供 1688.items.onsale.get/taobao.item_search_shop 接口&#xff0c;可批量获取店铺在售商品列表&#xff0c;包含商品 ID、标题、价格、销量、图片等核心信息。该接口适用于商品库管理、竞品监控、数据分析等场景 ​二、接口调用流程 前期准…...

【C#学习笔记02】基本元素与数据类型

引言 深入了解C语言的基本元素、计算机存储器结构、常量与变量的概念以及数据类型。这些内容是C语言编程的基础&#xff0c;掌握它们对于编写高效、可靠的嵌入式程序至关重要。 1.C语言的基本元素 ​编程语言的发展离不开自然语言&#xff0c;所以编程语言的语法和词汇也是由…...

【语料数据爬虫】Python爬虫|批量采集工作报告数据(1)

前言 本文是该专栏的第4篇,后面会持续分享Python爬虫采集各种语料数据的的干货知识,值得关注。 在本文中,笔者将主要来介绍基于Python,来实现批量采集“工作报告”数据。同时,本文也是采集“工作报告”数据系列的第1篇。 采集相关数据的具体细节部分以及详细思路逻辑,笔…...

<建模软件安装教程1>Blender4.2系列

Blender4.2安装教程 0注意&#xff1a;Windows环境下安装 第一步&#xff0c;百度网盘提取安装包。百度网盘链接&#xff1a;通过网盘分享的文件&#xff1a;blender.zip 链接: https://pan.baidu.com/s/1OG0jMMtN0qWDSQ6z_rE-9w 提取码: 0309 --来自百度网盘超级会员v3的分…...

Docker极简部署开源播放器Splayer结合内网穿透远程流畅在线听歌

前言 嘿&#xff0c;各位音乐发烧友们&#xff01;如果你厌倦了广告的打扰&#xff0c;渴望在忙碌的生活中找到一片宁静的音乐天地&#xff0c;那么今天这篇教程绝对适合你——如何在Ubuntu上用Docker快速搭建一款高颜值、无广告的某抑云音乐播放器Splayer。 Splayer不仅界面…...

基于YOLO(以YOLOv8为例)模型开发算法的详细步骤,包含算法代码、训练指导、数据集准备以及可能的改进方向

以下是一个基于YOLO&#xff08;以YOLOv8为例&#xff09;模型开发算法的详细步骤&#xff0c;包含算法代码、训练指导、数据集准备以及可能的改进方向。 1. 环境准备 首先&#xff0c;你需要安装必要的库。可以使用以下命令创建一个新的虚拟环境并安装所需的库&#xff1a; …...

显示器长时间黑屏

现象 电脑启动后,进入登录界面前会随机黑屏,有时候十几秒,有时候几分钟 进入桌面后,长时间不操作电脑黑屏,移动鼠标,点击键盘后尝试点亮屏幕,也会消耗较长时间 尝试 重装系统,或者重新安装显卡,都能够恢复,但过段时间以后又出现黑屏情况 集成显卡,独立显卡都出现过 操作系统…...

linux docker相关指令

1、镜像操作 0&#xff09;、搜索&#xff1a;docker search 镜像名称 1&#xff09;、拉取&#xff1a;docker pull 2&#xff09;、推送&#xff1a;docker push 3&#xff09;、查看&#xff1a;docker images 4&#xff09;、查看所有镜像ID&#xff1a;d…...

V8引擎中的垃圾回收机制如何工作?

V8引擎中的垃圾回收机制主要通过分代回收和增量标记清除算法来管理内存。以下是其工作原理的详细说明&#xff1a; V8 的垃圾回收机制基于以下核心设计原则&#xff1a; 1. 分代假设&#xff1a;大多数对象的生命周期很短&#xff0c;只有少数对象会存活较长时间&#xff1b;…...

内网安全-横向移动PTH 哈希PTT 票据PTK 密匙Kerberos密码喷射

一.域横向pth&#xff0c;mimkatz&#xff0c;NTLM windwos server 2012 R2之前可能是NTLM和LM&#xff0c;之后为NTLM 1.mimkatz ptk 使用mimkatz进行横向移动 mimikatz sekurlsa::pth /user:administrator&#xff08;目标本地用户名&#xff09; /domain:192.168.3.32&a…...

自然语言处理文本分析:从词袋模型到认知智能的进化之旅

清晨&#xff0c;当智能音箱准确识别出"播放周杰伦最新专辑"的模糊语音指令时&#xff1b;午间&#xff0c;企业舆情系统自动标记出十万条评论中的负面情绪&#xff1b;深夜&#xff0c;科研人员用GPT-4解析百万篇论文发现新材料线索——这些场景背后&#xff0c;是自…...

洛谷 P2234:[HNOI2002] 营业额统计 ← STL set

【题目来源】 https://www.luogu.com.cn/problem/P2234 【题目描述】 Tiger 最近被公司升任为营业部经理&#xff0c;他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。 Tiger 拿出了公司的账本&#xff0c;账本上记录了公司成立以来每天的营业额。分析…...

linux---天气爬虫

代码概述 这段代码实现了一个天气查询系统&#xff0c;支持实时天气、未来天气和历史天气查询。用户可以通过终端菜单选择查询类型&#xff0c;并输入城市名称来获取相应的天气信息。程序通过 TCP 连接发送 HTTP 请求&#xff0c;并解析返回的 JSON 数据来展示天气信息。 #in…...