NDIS驱动开发-NET_BUFFER体系

网络数据由通过网络发送或接收的数据包组成。 NDIS 提供数据结构来描述和组织此类数据。 NDIS 6.0 及更高版本的主要网络数据结构包括:

  • NET_BUFFER
  • NET_BUFFER LIST
  • NET_BUFFER_LIST_CONTEXT

它们之间的关系如下:

在 NDIS 6.0 及更高版本中, NET_BUFFER 是打包网络数据的基本构建基块。 每个NET_BUFFER结构都有一个 MDL 链。 MDL 将数据缓冲区的地址映射到NET_BUFFER结构指定的数据空间。 此数据映射与 NDIS 5.x 的 MDL 链相同, 更早版本的驱动程序在 NDIS_PACKET 结构中使用 。 NDIS 也提供用于操作 MDL 链的函数。

可以将多个NET_BUFFER结构附加到NET_BUFFER_LIST结构。 NET_BUFFER结构组织为以 NULL 结尾的单独链接列表。 只有源自 NET_BUFFER_LIST 结构的驱动程序(即 NDIS)应直接修改链接列表以插入和删除NET_BUFFER结构。

NET_BUFFER LIST 结构包含描述附加到列表的所有 NET_BUFFER 结构的信息。 如果驱动程序需要额外的空间来存储上下文信息,驱动程序可以将此类信息存储在NET_BUFFER_LIST_CONTEXT结构中。 NDIS 提供用于分配、释放和访问NET_BUFFER_LIST_CONTEXT结构中的数据的函数。

可以附加多个NET_BUFFER_LIST结构以形成NET_BUFFER_LIST结构的列表。 NET_BUFFER_LIST结构组织为以 NULL 结尾的单独链接列表。 驱动程序可以直接修改链接列表以插入和删除NET_BUFFER_LIST结构。

NET_BUFFER 结构

NDIS 6.0 及更高版本的 NET_BUFFER 结构类似于 NDIS 5 使用的 NDIS_PACKET 结构。x 和更早版本的驱动程序。 每个NET_BUFFER结构打包一个网络数据包。

下图显示了NET_BUFFER结构中的字段:

NET_BUFFER结构包括 NetBufferHeader 成员中的NET_BUFFER_HEADER结构。 NET_BUFFER_HEADER 结构包括 NetBufferData 成员中的NET_BUFFER_DATA结构, 应使用 NDIS 宏访问NET_BUFFER结构成员。 

某些 NET_BUFFER 结构成员仅由 NDIS 使用。 驱动程序通常使用的成员包括:

  • ProtocolReserved:保留供协议驱动程序使用;
  • MiniportReserved:保留供微型端口驱动程序使用;
  • NdisPoolHandle:指定池句柄,该句柄标识从中分配NET_BUFFER结构的NET_BUFFER池;
  • NEXT:指定指向NET_BUFFER结构链接列表中的下一个NET_BUFFER结构的指针。 如果这是列表中的最后一个NET_BUFFER结构,则此成员为 NULL;
  • DataLength:指定 MDL 链中网络数据的长度(以字节为单位);
  • DataOffset:指定从 MDL 链中内存开始到 MDL 链中网络数据开始的偏移量(以字节为单位);
  • CurrentMdl:指定指向当前驱动程序正在使用的第一个 MDL 的指针。 此指针提供一种优化,通过跳过当前驱动程序未使用的任何 MDL 来提高性能;
  • CurrentMdlOffset:指定 MDL 中已用数据空间开头的偏移量(以字节为单位),该偏移量由 NET_BUFFER 结构的 CurrentMdl 成员指定;

下图显示了 CurrentMdl、 CurrentMdlOffset、 DataOffset 和 DataLength 成员与数据空间之间的关系:

 

NDIS 提供用于管理 MDL 链中的数据空间的函数。 驱动程序如何使用数据空间与当前驱动程序一起动态更改。 有时,当前驱动程序当前未使用的数据空间。 尽管未使用的数据空间当前未使用,但它可以包含有效数据。 例如,在接收路径上, 未使用的数据空间可以包含较低级别驱动程序使用的信息。

以下术语和定义描述了 NET_BUFFER 数据空间的元素:

  • 已用数据空间:已用数据空间 包含当前驱动程序当前使用的数据。 驱动程序通过撤退操作增加 已用数据空间 ,并通过高级操作减少 已用数据空间;
  • 未使用的数据空间:当前驱动程序当前未使用此数据空间;
  • 数据总大小:总数据大小是 已用数据空间 与 未使用数据空间大小之和。 若要计算总大小,请将 DataOffset 添加到 DataLength ;
  • 撤退:撤退操作会增加 已用数据空间的大小;
  • 前进:前进操作会减小 已用数据空间的大小;
 NET_BUFFER_LIST结构

NET_BUFFER_LIST结构包含NET_BUFFER结构的链接列表。下图显示了NET_BUFFER_LIST结构中的字段:

NET_BUFFER_LIST结构包括 NetBufferListHeader 成员中的NET_BUFFER_LIST_HEADER结构。 NET_BUFFER_LIST_HEADER结构包括 NetBufferListData 成员中的NET_BUFFER_LIST_DATA结构。 应使用 NDIS 宏访问NET_BUFFER_LIST结构成员。 

某些成员仅由 NDIS 使用。 驱动程序最有可能使用的成员在以下列表中定义:

  • ParentNetBufferList:如果 NET_BUFFER_LIST 结构是从克隆、分段或重新组合的父类派生的子级, 则 ParentNetBufferList 指定指向父NET_BUFFER_LIST结构的指针。 否则,此参数为 NULL;
  • NdisPoolHandle:指定池句柄,该句柄标识从中分配NET_BUFFER_LIST结构的NET_BUFFER_LIST池;
  • ProtocolReserved:保留供协议驱动程序使用;
  • MiniportReserved:保留供微型端口驱动程序使用;
  • SourceHandle:NDIS 使用以下驱动程序提供的例程之一在绑定或附加操作中提供给驱动程序的句柄:微型端口驱动程序:MiniportInitializeEx、协议驱动程序:ProtocolBindAdapterEx、Filter驱动程序:FilterAttach。NDIS 使用 SourceHandle 将NET_BUFFER_LIST结构返回到发送NET_BUFFER_LIST结构的驱动程序。 NDIS 驱动程序不应读取此句柄;
  • ChildRefCount:如果 NET_BUFFER_LIST 结构是父类(具有由克隆、片段或重新组合操作) 派生的子级, 则 ChildRefCount 指定现有子级的数目。 否则此参数为零;
  • Flags:保留用于NET_BUFFER_LIST结构的属性的未来规范。 目前没有可用于驱动程序的标志;
  • Status:指定此NET_BUFFER_LIST结构的网络数据操作的最终完成状态。 微型端口驱动程序在完成发送操作之前写入此值;
  • NetBufferListInfo:指定 列表中 所有NET_BUFFER结构通用 NET_BUFFER_LIST 结构信息。 此信息通常称为“带外 (OOB) 数据”;
  • Next: 指定指向NET_BUFFER_LIST结构链接列表中的下一个NET_BUFFER_LIST结构的指针。 如果NET_BUFFER_LIST结构是列表中的最后一个结构,则此成员为 NULL;
  • FirstNetBuffer:指定指向与此NET_BUFFER_LIST结构关联的NET_BUFFER结构链接列表中的第一个NET_BUFFER结构的指针;

注意Context 是指向 NET_BUFFER_LIST_CONTEXT 结构的指针。 NDIS 提供宏和函数来操作上下文中的数据。

NET_BUFFER_LIST_CONTEXT结构

NDIS 驱动程序使用 NET_BUFFER_LIST_CONTEXT 结构来存储与 NET_BUFFER_LIST 结构关联的其他数据。 NET_BUFFER_LIST 结构的 Context 成员是指向NET_BUFFER_LIST_CONTEXT结构的指针。 存储在NET_BUFFER_LIST_CONTEXT结构中的信息对堆栈中的 NDIS 和其他驱动程序是不透明的。

下图显示了NET_BUFFER_LIST_CONTEXT结构中的字段:

NET_BUFFER_LIST_CONTEXT结构包括包含上下文数据的 ContextData 成员。 此数据可以是驱动程序 NET_BUFFER_LIST结构所需的 任何上下文信息。

驱动程序应使用以下 NDIS 宏和函数来访问和操作NET_BUFFER_LIST_CONTEXT结构中的成员:

NdisAllocateNetBufferListContext

NdisFreeNetBufferListContext

NET_BUFFER_LIST_CONTEXT_DATA_START

NET_BUFFER_LIST_CONTEXT_DATA_SIZE

发送网络数据

下图演示了一个基本的发送操作,该操作涉及协议驱动程序、NDIS 和微型端口驱动程序:

协议驱动程序调用 NdisSendNetBufferLists 函数以发送绑定上的 NET_BUFFER_LIST 结构。 NDIS 调用微型端口驱动程序的 MiniportSendNetBufferLists 函数,将NET_BUFFER_LIST结构转发到基础微型端口驱动程序。

所有基于NET_BUFFER的发送操作都是异步的。 完成时,微型端口驱动程序使用适当的状态代码调用 NdisMSendNetBufferListsComplete 函数。 每个NET_BUFFER_LIST结构的发送可以单独完成。 每次微型端口驱动程序调用 NdisMSendNetBufferListsComplete 时,NDIS 都会调用协议驱动程序的 ProtocolSendNetBufferListsComplete 函数。

一旦 NDIS 调用协议驱动程序的 ProtocolSendNetBufferListsComplete 函数,协议驱动程序就可以回收NET_BUFFER_LIST结构以及所有相关结构和数据的所有权。

微型端口驱动程序或 NDIS 可以按任意顺序返回 NET_BUFFER_LIST 结构。 协议驱动程序保证未修改附加到每个 NET_BUFFER_LIST 结构的NET_BUFFER结构列表。

任何 NDIS 驱动程序都可以在NET_BUFFER_LIST结构中分离NET_BUFFER结构。 任何 NDIS 驱动程序还可以在NET_BUFFER结构中分离 MDL。 但是,驱动程序必须始终返回具有原始形式的NET_BUFFER结构和 MDL 的NET_BUFFER_LIST结构。 例如,中间驱动程序可以将NET_BUFFER_LIST分成两个新的NET_BUFFER_LIST结构,并将部分原始数据传递给下一个驱动程序。 但是,当中间驱动程序完成原始NET_BUFFER_LIST它必须返回包含原始NET_BUFFER结构和 MDL 的完整NET_BUFFER_LIST。

协议驱动程序将 NET_BUFFER_LIST 结构中的 SourceHandle 成员设置为 NDIS 在调用 NdisOpenAdapterEx 函数时提供的 NdisBindingHandle。 NDIS 使用 SourceHandle 成员将NET_BUFFER_LIST结构返回到发送NET_BUFFER_LIST结构的协议驱动程序。

中间驱动程序还会将 NET_BUFFER_LIST 结构中的 SourceHandle 成员设置为 NDIS 在调用 NdisOpenAdapterEx 时提供的 NdisBindingHandle 值。 如果中间驱动程序转发发送请求,则驱动程序必须在写入 SourceHandle 成员之前保存过度驱动程序提供的 SourceHandle 值。 当 NDIS 将转发NET_BUFFER_LIST结构返回到中间驱动程序时,中间驱动程序必须还原它保存的 SourceHandle 。

接收网络数据

下图演示了一个基本的接收操作,该操作涉及微型端口驱动程序、NDIS 和协议驱动程序。

微型端口驱动程序调用 NdisMIndicateReceiveNetBufferLists 函数,以指示更高级别驱动程序 NET_BUFFER 结构。 每个NET_BUFFER结构通常应附加到单独的 NET_BUFFER_LIST 结构。 这样,协议驱动程序就可以创建NET_BUFFER_LIST结构的原始列表的子集,并将其转发到不同的客户端。 某些驱动程序(例如本机 IEEE 802.11 微型端口驱动程序)可能会将多个NET_BUFFER结构附加到NET_BUFFER_LIST结构。

链接所有NET_BUFFER_LIST结构后,微型端口驱动程序会将指向列表中第一个NET_BUFFER_LIST结构的指针传递给 NdisMIndicateReceiveNetBufferLists 函数。 NDIS 检查NET_BUFFER_LIST结构,并调用与NET_BUFFER_LIST结构关联的每个协议驱动程序的 ProtocolReceiveNetBufferLists 函数。 NDIS 传递列表的子集,该子集仅包含与每个协议驱动程序的正确绑定关联的NET_BUFFER_LIST结构。 NDIS 将 NET_BUFFER_LIST 结构中指定的 NetBufferListFrameType 值与每个协议驱动程序注册的帧类型匹配。

如果设置了传递给协议驱动程序的 ProtocolReceiveNetBufferLists 函数的 ReceiveFlags 参数中的NDIS_RECEIVE_FLAGS_RESOURCES标志,则 NDIS 会在 ProtocolReceiveNetBufferLists 调用返回后立即重新获得NET_BUFFER_LIST结构的所有权。

注意 如果设置了NDIS_RECEIVE_FLAGS_RESOURCES标志,则协议驱动程序必须在链接列表中保留原始NET_BUFFER_LIST结构集。 例如,设置此标志时,驱动程序可能会处理这些结构,并指示它们一次上堆栈一个,但在函数返回之前,它必须还原原始链接列表。

如果未设置传递给协议驱动程序 ProtocolReceiveNetBufferLists 函数的 ReceiveFlags 参数中的NDIS_RECEIVE_FLAGS_RESOURCES标志,则协议驱动程序可以保留NET_BUFFER_LIST结构的所有权。 在这种情况下,协议驱动程序必须通过调用 NdisReturnNetBufferLists 函数返回NET_BUFFER_LIST结构。

如果微型端口驱动程序在接收资源上运行不足,则可以在调用 NdisMIndicateReceiveNetBufferLists 时在 ReceiveFlags 参数中设置NDIS_RECEIVE_FLAGS_RESOURCES标志。 在这种情况下,驱动程序可以在 NdisMIndicateReceiveNetBufferLists 返回后立即回收所有指示NET_BUFFER_LIST结构和嵌入NET_BUFFER结构的所有权。 指示设置了NDIS_RECEIVE_FLAGS_RESOURCES标志的NET_BUFFER结构会强制协议驱动程序复制数据,因此应避免这样做。 微型端口驱动程序应检测即将耗尽接收资源的时间,并采取任何必要的步骤来避免这种情况。

NDIS 在协议驱动程序调用 NdisReturnNetBufferLists 后,调用微型端口驱动程序的 MiniportReturnNetBufferLists 函数。

注意 如果微型端口驱动程序指示NET_BUFFER_LIST结构并设置了NDIS_RECEIVE_FLAGS_RESOURCES标志,这并不意味着 NDIS 会向具有相同状态的协议驱动程序指示NET_BUFFER_LIST结构。 例如,NDIS 可以复制设置了 NDIS_RECEIVE_FLAGS_RESOURCES 标志的NET_BUFFER_LIST结构,并在清除标志的情况下指示复制到协议驱动程序。

NDIS 可以任意顺序 和 任意组合将NET_BUFFER_LIST结构返回到微型端口驱动程序。 也就是说,通过调用 MiniportReturnNetBufferLists 函数返回给微型端口驱动程序的NET_BUFFER_LIST结构的链接列表可以具有以前对 NdisMIndicateReceiveNetBufferLists 的不同调用NET_BUFFER_LIST结构。

微型端口驱动程序应将 NET_BUFFER_LIST 结构中的 SourceHandle 成员设置为 NDIS 在 MiniportInitializeEx 函数中提供给微型端口驱动程序的 MiniportAdapterHandle。 筛选器驱动程序必须将筛选器驱动程序源自的每个NET_BUFFER_LIST结构的 SourceHandle 成员设置为筛选器的 NdisFilterHandle ,NDIS 在 FilterAttach 函数中提供给筛选器驱动程序。 筛选器驱动程序不得修改任何非筛选器驱动程序产生的NET_BUFFER_LIST结构中的 SourceHandle 成员。

中间驱动程序还将 NET_BUFFER_LIST 结构中的 SourceHandle 成员设置为 MiniportAdapterHandle 值,NDIS 在 MiniportInitializeEx 函数中提供给中间驱动程序。 如果中间驱动程序转发接收指示,则驱动程序必须在写入 SourceHandle 成员之前保存基础驱动程序提供的 SourceHandle 值。 当 NDIS 将转发NET_BUFFER_LIST结构返回到中间驱动程序时,中间驱动程序必须还原它保存的 SourceHandle 。

收发网络数据包的代码

下面是实际使用的一个发送数据包的例子:

PNET_BUFFER_LIST CreateBroadCast(
IN NDIS_HANDLE FilterHandle, 
IN UCHAR Buffer[MAX_BOASTCAST]
)
{

	PUCHAR               pData          = NULL;
	PUCHAR               pMdlData       = NULL;
	PMDL                 pMdl           = NULL;
	PNET_BUFFER_LIST     pNetBufferList = NULL;

	// 分配一个内存
	pData = (PUCHAR)NdisAllocateMemoryWithTagPriority(
            FilterHandle, 
            MAX_BOASTCAST, 
            ALLOC_TAG, 
            LowPoolPriority);

    // 分配MDL
	pMdl = NdisAllocateMdl(FilterHandle, pData, FILTER_ALLOC_TAG);

    // 获取MDL的地址
	pMdlData = (PUCHAR)MmGetSystemAddressForMdlSafe(pMdl, LowPoolPriority);
	
    // 将数据复制到MDL
	NdisMoveMemory(pMdlData, &Buffer[0], MAX_BOASTCAST);

    // 创建一个NetBufferList
	pNetBufferList = NdisAllocateNetBufferAndNetBufferList(
                                pFilter->SendNetBufferListPool,
                                0,
                                0,           // back fill size
                                pMdl,
                                0,          // Data offset
                                MAX_BOASTCAST);

	pNetBufferList->SourceHandle = pFilter->FilterHandle;
	
	return pNetBufferList;
}

以及接收数据包的例子:

ULONG AnalysisNetBuffer(
IN NDIS_HANDLE pFilter, 
IN PNET_BUFFER_LIST NetBufferLists
)
{
	PUCHAR				pData      = NULL;
	PNET_BUFFER_LIST	pCurrNbl   = NetBufferLists;
	PNET_BUFFER			pCurrBuff  = NULL;
	PNET_BUFFER         pNextBuff  = NULL;   
	PMDL				pMdl       = NULL;
	
	ULONG				ulOffset   = 0;
	int					nDataLen   = 0;
	ULONG               ulError    = FC_GIGE_SUCCESS;

	while (pCurrNbl)
	{
		pCurrBuff = NET_BUFFER_LIST_FIRST_NB(pCurrNbl);
 
		while(pCurrBuff)
		{
			ulOffset  = NET_BUFFER_DATA_OFFSET(pCurrBuff);
			pMdl      = NET_BUFFER_FIRST_MDL(pCurrBuff);
			nDataLen  = NET_BUFFER_DATA_LENGTH(pCurrBuff);
			
			if(pMdl == NULL || nDataLen == 0) continue;
 
            pData     = (UCHAR*)MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
			pNextBuff = NET_BUFFER_NEXT_NB(pCurrBuff);
			if(NULL == pNextBuff)
			{
				// 获取真正的数据地址,此处的pData指向的就是数据地址
				pData    = pData + ulOffset;
				nDataLen = nDataLen - ulOffset;
			}
			else
			{
				;
			}
			pCurrBuff = pNextBuff;
		}
		pCurrNbl = NET_BUFFER_LIST_NEXT_NBL(pCurrNbl);
	}
	
	return ulError;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于python数据挖掘在淘宝评价方面的应用与分析,技术包括kmeans聚类及情感分析、LDA主题分析

随着电子商务的蓬勃发展,淘宝作为中国最大的在线购物平台之一,吸引了大量的消费者进行购物并留下了大量的客户评价。这些客户评价中包含了丰富的消费者意见和情感信息,对于商家改进产品、提升服务质量以及消费者决策都具有重要的参考价值。 …

一个机器学习问题的重新定义

任何事物都有两面性。 一些机器学习问题也是如此。并非每个回归问题(你认为的)都需要回归。仔细考虑和审视问题的业务不仅可以帮助开发更好的模型,还可以找到有效的解决方案。 重构或重新定义(reframing)是一种改变机…

数据结构-思考完全二叉树

我们知道在完全二叉树中 : (孩子下标-1)/ 2 父节点下标 父节点下标*21 左孩子节点 父节点下标*22 右孩子节点 那我们该怎样理解以便之后不容易忘记呢? 以下是我的思考过程:观察下边的完全二叉树的下标规律…

Docker HTTPS api V2 Manifest V 2, Schema 2 下的免装docker下载镜像的方法

目录 前言 下载镜像代码 使用方法 原代码中无法适配 Schema 2 的原因浅析 如何解决 相对原代码改动的东西 前言 本文提供代码主要是基于 https://github.com/NotGlop/docker-drag 提供的代码修改的。链接中提供的代码应该是是基于HTTPS api V2 Manifest V 2, Schema 1实…

如何使用pycrypt加密工具测试反病毒产品的检测性能

关于pycrypt pycrypt是一款基于Python 3语言开发的加密工具,广大研究人员可以使用该工具来尝试绕过任意类型的反病毒产品,以检测目标反病毒产品的安全性能。 功能介绍 1、目前已知反病毒产品检测率为0/40; 2、支持绕过任意EDR解决方案&#…

Nodejs+Socket.io+Web端完成聊天

前言 源码获取:nodeexpresssocket.ioweb: 聊天demo (gitee.com) 目录结构 后端依赖 启动方式 前端是html正常启动 后端是node app.js 后端app.js核心代码 const express require(express) const app express() var http require(http).Server(app) var io require(so…

AI网络爬虫-自动获取百度实时热搜榜

工作任务和目标&#xff1a;自动获取百度实时热搜榜的标题和热搜指数 标题&#xff1a;<div class"c-single-text-ellipsis"> 东部战区台岛战巡演练模拟动画 <!--48--></div> <div class"hot-index_1Bl1a"> 4946724 </div> …

uniapp+vue3+ts开发小程序或者app架构时候的UI框架选型

使用vue3tsviteuniapp开发小程序或者跨平台app的趋势越来越高&#xff0c;有一个顺手的UI的框架还是非常重要的&#xff0c;官方维护的 uni-ui&#xff0c;支持全端&#xff0c;而且有类型提示&#xff0c;目前已经内置到 GitHub - Sjj1024/uniapp-vue3: 使用uniapp和vue3 ts …

01-05.Vue自定义过滤器

目录 前言过滤器的概念过滤器的基本使用给过滤器添加多个参数 前言 我们接着上一篇文章01-04.Vue的使用示例&#xff1a;列表功能 来讲。 下一篇文章 02-Vue实例的生命周期函数 过滤器的概念 概念&#xff1a;Vue.js 允许我们自定义过滤器&#xff0c;可被用作一些常见的文本…

Photoshop插件(UXP)编写过程中,如何更新sp-checkbox的选中状态

✨问题说明 sp-checkbox是uxpSpectrum UXP Widgets下的一个小组件&#xff0c;内置样式大概是这样&#xff1a; 那么&#xff0c;如果用js动态的改变选中的状态&#xff0c;应该如何做呢&#xff1f; 如果直接是html来写&#xff1a; <sp-checkbox checked>Checked<…

部门来了个测试开发,听说是00后,上来一顿操作给我看蒙了...

公司新来了个同事&#xff0c;听说大学是学的广告专业&#xff0c;因为喜欢IT行业就找了个培训班&#xff0c;后来在一家小公司实习半年&#xff0c;现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍&#xff0c;服务器缩减一半&#xff0c;性能反而提升4倍&#xff01…

Java——图书管理系统万字详解(附代码)

框架搭建 book包 将书相关的放到book包中&#xff0c;创建一个Book类用来设置书的属性&#xff0c;包括书名、作者、价格、类型、是否被借出等。 以上属性均被private所修饰 利用编译器生成构造方法&#xff08;不需要构造isBorrowed&#xff0c;因为其初始值为false&#…

代码审计--一道简单的文件包含题目的多种利用方式

NO.1 传统方法 首先来看下代码 <?php error_reporting(0); if(isset($_GET["file"])){include($_GET["file"]); }else{highlight_file(__FILE__);phpinfo(); } ?>看完代码后再来学习学习函数吧&#xff0c;毕竟菜啊&#xff01;&#xff01;&…

【图书推荐】《Vue.js 3.x+Element Plus从入门到精通(视频教学版)》

配套示例源码与PPT课件下载 百度网盘链接: https://pan.baidu.com/s/1nBQLd9UugetofFKE57BE5g?pwdqm9f 自学能力强的&#xff0c;估计不要书就能看代码学会吧。 内容简介 本书通过对Vue.js&#xff08;简称Vue&#xff09;的示例和综合案例的介绍与演练&#xff0c;使读者…

【独家揭秘!玩转ChatGPT?一文带你解锁秘籍!】

&#x1f680;【独家揭秘&#xff01;玩转ChatGPT&#xff1f;一文带你解锁秘籍&#xff01;】&#x1f680; &#x1f449; 【直达ChatGPT体验站】 ChatGPT&#xff0c;全称“Chat Generative Pre-trained Transformer”&#xff0c;是人工智能研究实验室OpenAI于2022年底推出…

夏日炎炎,手机如何避免变成热源?这些降温技巧分享给你

夏日炎炎&#xff0c;手机也容易“中暑”。 高温不仅会让手机性能大打折扣&#xff0c;还可能引发安全隐患。因此&#xff0c;如何让手机在高温下“冷静”下来&#xff0c;成为了许多手机用户关心的问题。 本文将为你提供一些实用的降温技巧&#xff0c;帮助你的手机安全度过…

Python数据可视化(四)

实现图形的动画效果 在 matplotlib 中&#xff0c;不仅可以绘制静态图形&#xff0c;也可以绘制动态图形。对于动态图形来说&#xff0c;我们称 之为动画或许会让读者更容易明白。绘制动画的方法主要有两种&#xff1a;一种是使用模块 animation 绘制动 画&#xff1b;另一种是…

【C++题解】1699 - 输出是2的倍数,但非3的倍数的数

问题&#xff1a;1699 - 输出是2的倍数&#xff0c;但非3的倍数的数 类型&#xff1a;循环 题目描述&#xff1a; 请从键盘读入一个整数 n&#xff0c;输出 1∼n 中所有是 2 的倍数&#xff0c;但非 3 的倍数的数&#xff0c;每行 1个。 比如&#xff0c;读入一个整数10 &…

[Algorithm][动态规划][简单多状态DP问题][按摩师][打家劫舍Ⅱ][删除并获得点数][粉刷房子]详细讲解

目录 1.按摩师1.题目链接2.算法思路详解3.代码实现 2.打家劫舍 II1.题目链接2.算法思路详解3.代码实现 3.删除并获得点数1.题目链接2.算法思路详解3.代码实现 4.粉刷房子1.题目链接2.算法思路详解3.代码实现 1.按摩师 1.题目链接 按摩师 2.算法思路详解 思路&#xff1a; 确…

2024 ISCC pwn wp

iscc 练武pwn 总结第一周chaosISCC_easyFlagshopping 第二周ISCC_easyISCC_Uheapheap 第三周miaoYour_programeazy_heap 总结 总体感觉iscc考察的题目都挺基础的&#xff0c;在目前这种比赛的大环境下&#xff0c;仍然出这种&#xff0c;比较基础的题目&#xff0c;实在是难得…