windows USB 驱动开发-URB结构

通用串行总线 (USB) 客户端驱动程序无法直接与其设备通信。 相反,客户端驱动程序会创建请求并将其提交到 USB 驱动程序堆栈进行处理。 在每个请求中,客户端驱动程序提供一个可变长度的数据结构,称为 USB 请求块 (URB) ,URB 结构描述请求的详细信息,还包含有关已完成请求状态的信息。 客户端驱动程序通过 URL 执行所有特定于设备的操作,包括数据传输。 在将请求提交到 USB 驱动程序堆栈之前,客户端驱动程序必须使用有关请求的信息初始化 URB。 对于某些类型的请求,Microsoft 提供帮助程序例程和宏,这些例程和宏分配 URB 结构,并使用客户端驱动程序提供的详细信息填充 URB 结构的必要成员。

每个 URB 都以标准固定大小的标头开头, (_URB_HEADER) ,其用途是标识请求的操作类型。 _URB_HEADER 的 Length 成员指定 URB 的大小(以字节为单位)。 Function 成员必须是一系列系统定义的URB_FUNCTION_XXX常量之一,用于确定所请求的操作类型。 例如,在数据传输的情况下,此成员指示传输的类型。 函数代码URB_FUNCTION_CONTROL_TRANSFER、URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER和URB_FUNCTION_ISOCH_TRANSFER分别指示控制、批量/中断和常时等量传输。 USB 驱动程序堆栈使用 Status 成员返回特定于 USB 的状态代码。

为了提交 URB,客户端驱动程序使用 IOCTL_INTERNAL_USB_SUBMIT_URB 请求,该请求通过 I/O 请求数据包 (IRP) 类型IRP_MJ_INTERNAL_DEVICE_CONTROL传递到设备。

USB 驱动程序堆栈处理完 URB 后,驱动程序堆栈将使用 URB 结构的 Status 成员返回特定于 USB 的状态代码。

KMDF 和 UMDF 驱动程序开发人员应使用相应的框架接口来与 USB 设备通信。 

分配和构建 URB

USB 客户端驱动程序可以使用 Windows 驱动程序模型 (WDM) 驱动程序例程来分配 URB 并格式化 URB,然后再将请求发送到 Microsoft 提供的 USB 驱动程序堆栈。

客户端驱动程序使用 URB 打包 USB 驱动程序堆栈中较低级驱动程序处理请求所需的所有信息。 在 Windows 操作系统中,URB 在 URB 结构中描述。

Microsoft 为 USB 客户端驱动程序提供了例程库。 通过使用这些例程,USB 客户端驱动程序可以为某些指定操作生成 URB 请求,并将其转发到 USB 堆栈中。 如果愿意,可以将客户端驱动程序设计为为支持的操作调用库例程,而不是生成自己的 URB 请求。

Windows 7 及更早版本中的 URB 分配

若要使用适用于 Windows 7 及更早版本的 Windows 的 Windows 驱动程序工具包 (WDK) 中包含的例程发送 USB 请求,客户端驱动程序通常会分配和填充 URB 结构,将 URB 结构与新的 IRP 相关联,并将 IRP 发送到 USB 驱动程序堆栈。

对于某些类型的请求,Microsoft 提供 (由分配 URB 结构的Usbd.sys) 导出的帮助程序例程。 例如, USBD_CreateConfigurationRequestEx 例程为 URB 结构分配内存,为选择配置请求设置 URB 格式,并将 URB 结构的地址返回到客户端驱动程序。 但是,帮助程序例程不能用于所有类型的请求。

Microsoft 还提供了为某些类型的请求设置 URL 格式的宏。 对于这些宏,客户端驱动程序必须通过调用 ExAllocatePoolWithTag 来分配 URB 结构,或者在堆栈上分配 结构。 例如,在客户端驱动程序分配 URB 后,驱动程序可以调用 UsbBuildSelectConfigurationRequest 来格式化选择配置请求的 URB 或清除配置。

对于其他请求,客户端驱动程序必须根据请求类型,通过设置 URB 结构的各个成员来手动分配 和格式化 URB 。

USB 请求完成后,客户端驱动程序必须释放 URB 结构。 如果在堆栈上分配 URB,则 URB 在超出范围时释放。 如果在非分页池中分配 URB,则客户端驱动程序必须调用 ExFreePool 才能释放 URB。

Windows 8中的 URB 分配

WDK for Windows 8 提供了一个新的静态库 Usbdex.lib,用于导出用于分配、格式化和释放 URL 的例程。 此外,还有一种将 URB 与 IRP 相关联的新方法。 新的例程可由面向 Windows Vista 和更高版本的 Windows 的客户端驱动程序调用。

在 Windows Vista 及更高版本上运行的客户端驱动程序必须使用新的例程,以便基础 USB 驱动程序堆栈可以利用某些性能和可靠性改进。 这些改进适用于 Windows 8 中为支持 USB 3.0 设备和主机控制器而引入的新 USB 驱动程序堆栈。 对于 USB 2.0 主控制器,Windows 加载不支持改进的驱动程序堆栈的早期版本。 无论基础驱动程序堆栈的版本或主机控制器支持的协议版本如何,都必须始终调用新的 URB 例程。

在调用任何新例程之前,请确保有一个 USBD 句柄,用于向 USB 驱动程序堆栈注册客户端驱动程序。 若要获取 USBD 句柄, 请调用 USBD_CreateHandle。

WDK 提供以下例程,用于Windows 8。 这些例程在 Usbdlib.h 中定义。

  • USBD_UrbAllocate
  • USBD_IsochUrbAllocate
  • USBD_SelectConfigUrbAllocateAndBuild
  • USBD_SelectInterfaceUrbAllocateAndBuild
  • USBD_UrbFree
  • USBD_AssignUrbToIoStackLocation

前面列表中的分配例程返回指向由 USB 驱动程序堆栈分配的新 URB 结构的指针。 根据 Windows 加载的 USB 驱动程序堆栈的版本, URB 结构可以与不透明的 URB 上下文配对。 URB 上下文是有关 URB 的信息块。 无法查看 URB 标头的内容;这些信息旨在由 USB 驱动程序堆栈在内部使用,以改善 URB 跟踪和处理。 URB 上下文仅由 USB 驱动程序堆栈用于Windows 8。 如果 URB 上下文可用,USB 驱动程序堆栈会使用它使 URB 处理更安全、更高效。 例如,USB 驱动程序堆栈必须确保客户端驱动程序不会提交 URB,然后尝试在第一个请求完成之前重复使用同一 URB。 为了检测此类错误,USB 驱动程序堆栈会将状态信息存储在 URB 上下文中。 如果没有状态信息,USB 驱动程序堆栈将不得不将传入的 URB 与当前正在进行的所有 URB 进行比较。 当客户端驱动程序尝试释放 URB 时,USB 驱动程序堆栈也会使用状态信息。 在释放 URB 之前,USB 驱动程序堆栈会验证状态,以确保 URB 未挂起。

URB 上下文提供用于存储额外 URB 信息的官方机制。 使用 URB 上下文比根据需要分配额外的内存或在 URB 结构的保留成员中存储额外信息更可取。 USB 驱动程序堆栈在非分页池中分配 URB 及其关联的 URB 上下文,以便将来如果需要更大的 URB 上下文,唯一需要调整的是池分配的大小。

URB的结构
typedef struct _URB {union {
#if ..._URB_HEADER                                     UrbHeader;
#elsestruct _URB_HEADER                              UrbHeader;
#endif
#if ..._URB_SELECT_INTERFACE                           UrbSelectInterface;
#elsestruct _URB_SELECT_INTERFACE                    UrbSelectInterface;
#endif
#if ..._URB_SELECT_CONFIGURATION                       UrbSelectConfiguration;
#elsestruct _URB_SELECT_CONFIGURATION                UrbSelectConfiguration;
#endif
#if ..._URB_PIPE_REQUEST                               UrbPipeRequest;
#elsestruct _URB_PIPE_REQUEST                        UrbPipeRequest;
#endif
#if ..._URB_FRAME_LENGTH_CONTROL                       UrbFrameLengthControl;
#elsestruct _URB_FRAME_LENGTH_CONTROL                UrbFrameLengthControl;
#endif
#if ..._URB_GET_FRAME_LENGTH                           UrbGetFrameLength;
#elsestruct _URB_GET_FRAME_LENGTH                    UrbGetFrameLength;
#endif
#if ..._URB_SET_FRAME_LENGTH                           UrbSetFrameLength;
#elsestruct _URB_SET_FRAME_LENGTH                    UrbSetFrameLength;
#endif
#if ..._URB_GET_CURRENT_FRAME_NUMBER                   UrbGetCurrentFrameNumber;
#elsestruct _URB_GET_CURRENT_FRAME_NUMBER            UrbGetCurrentFrameNumber;
#endif
#if ..._URB_CONTROL_TRANSFER                           UrbControlTransfer;
#elsestruct _URB_CONTROL_TRANSFER                    UrbControlTransfer;
#endif
#if ..._URB_CONTROL_TRANSFER_EX                        UrbControlTransferEx;
#elsestruct _URB_CONTROL_TRANSFER_EX                 UrbControlTransferEx;
#endif
#if ..._URB_BULK_OR_INTERRUPT_TRANSFER                 UrbBulkOrInterruptTransfer;
#elsestruct _URB_BULK_OR_INTERRUPT_TRANSFER          UrbBulkOrInterruptTransfer;
#endif
#if ..._URB_ISOCH_TRANSFER                             UrbIsochronousTransfer;
#elsestruct _URB_ISOCH_TRANSFER                      UrbIsochronousTransfer;
#endif
#if ..._URB_CONTROL_DESCRIPTOR_REQUEST                 UrbControlDescriptorRequest;
#elsestruct _URB_CONTROL_DESCRIPTOR_REQUEST          UrbControlDescriptorRequest;
#endif
#if ..._URB_CONTROL_GET_STATUS_REQUEST                 UrbControlGetStatusRequest;
#elsestruct _URB_CONTROL_GET_STATUS_REQUEST          UrbControlGetStatusRequest;
#endif
#if ..._URB_CONTROL_FEATURE_REQUEST                    UrbControlFeatureRequest;
#elsestruct _URB_CONTROL_FEATURE_REQUEST             UrbControlFeatureRequest;
#endif
#if ..._URB_CONTROL_VENDOR_OR_CLASS_REQUEST            UrbControlVendorClassRequest;
#elsestruct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST     UrbControlVendorClassRequest;
#endif
#if ..._URB_CONTROL_GET_INTERFACE_REQUEST              UrbControlGetInterfaceRequest;
#elsestruct _URB_CONTROL_GET_INTERFACE_REQUEST       UrbControlGetInterfaceRequest;
#endif
#if ..._URB_CONTROL_GET_CONFIGURATION_REQUEST          UrbControlGetConfigurationRequest;
#elsestruct _URB_CONTROL_GET_CONFIGURATION_REQUEST   UrbControlGetConfigurationRequest;
#endif
#if ..._URB_OS_FEATURE_DESCRIPTOR_REQUEST              UrbOSFeatureDescriptorRequest;
#elsestruct _URB_OS_FEATURE_DESCRIPTOR_REQUEST       UrbOSFeatureDescriptorRequest;
#endif
#if ..._URB_OPEN_STATIC_STREAMS                        UrbOpenStaticStreams;
#elsestruct _URB_OPEN_STATIC_STREAMS                 UrbOpenStaticStreams;
#endif
#if ..._URB_GET_ISOCH_PIPE_TRANSFER_PATH_DELAYS        UrbGetIsochPipeTransferPathDelays;
#elsestruct _URB_GET_ISOCH_PIPE_TRANSFER_PATH_DELAYS UrbGetIsochPipeTransferPathDelays;
#endif};
} URB, *PURB;
URB 例程更新记录

下表汇总了 URB 例程中的更改。

如何提交 URB

客户端驱动程序使用 I/O 控制代码 (IOCTL) IOCTL 与设备通信,这些请求在 I/O 请求数据包 (IRP) 类型为 IRP_MJ_INTERNAL_DEVICE_CONTROL。 对于特定于设备的请求(如选择配置请求),与 IRP 关联的 USB 请求块 (URB) 中介绍了该请求。 将 URB 与 IRP 相关联并将请求发送到 USB 驱动程序堆栈的过程称为提交 URB。 若要提交 URB,客户端驱动程序必须使用 IOCTL_INTERNAL_USB_SUBMIT_URB 作为设备控制代码。 IOCTL 是提供 I/O 接口的“内部”控制代码之一,客户端驱动程序使用该接口来管理其设备和设备连接到的端口。 用户模式应用程序无权访问这些内部 I/O 接口。 

先决条件

在将请求发送到通用串行总线 (USB) 驱动程序堆栈之前,客户端驱动程序必须根据请求的类型分配 URB 结构和格式,如下步骤:

  • 通过调用 IoAllocateIrp 例程为 URB 分配 IRP。 必须提供接收 IRP 的设备对象的堆栈大小。 在对 IoAttachDeviceToDeviceStack 例程的上一次调用中,你收到了指向该设备对象的指针。 堆栈大小存储在 DEVICE_OBJECT 结构的 StackSize 成员中;
  • 通过调用 IoGetNextIrpStackLocation 获取指向 IRP 的第一个堆栈位置 (IO_STACK_LOCATION) 的指针;
  • 将 IO_STACK_LOCATION 结构的 MajorFunction 成员设置为IRP_MJ_INTERNAL_DEVICE_CONTROL;
  • 将 IO_STACK_LOCATION 结构的 Parameters.DeviceIoControl.IoControlCode 成员设置为IOCTL_INTERNAL_USB_SUBMIT_URB;
  • 将 IO_STACK_LOCATION 结构的 Parameters.Others.Argument1 成员设置为初始化的 URB 结构的地址。 若要将 IRP 关联到 URB,也可以仅当 URB 由 USBD_UrbAllocate、USBD_SelectConfigUrbAllocateAndBuild 或 USBD_SelectInterfaceUrbAllocateAndBuild 分配时才调用 USBD_AssignUrbToIoStackLocation;
  • 通过调用 IoSetCompletionRoutineEx 设置完成例程。如果异步提交 URB,请传递指向调用方实现的完成例程及其上下文的指针。 调用方在其完成例程中释放 IRP。如果要同步提交 IRP,请实现一个完成例程,并在调用 IoSetCompletionRoutineEx 时传递指向该例程的指针。 调用还需要 Context 参数中的初始化 KEVENT 对象。 在完成例程中,将 事件设置为信号状态;
  • 调用 IoCallDriver 将填充的 IRP 转发到设备堆栈中的下一个下一个设备对象。 对于同步调用,在调用 IoCallDriver 后,通过调用 KeWaitForSingleObject 来等待事件对象以获取事件通知;
  • 完成 IRP 后,检查 IRP 的 IoStatus.Status 成员并评估结果。 如果 IoStatus.Status STATUS_SUCCESS,则表示请求成功;
USB 同步提交

以下示例演示如何同步提交 URB。

// The SubmitUrbSync routine submits an URB synchronously.
//
// Parameters:
//      DeviceExtension: Pointer to the caller's device extension. The
//                       device extension must have a pointer to
//                       the next lower device object in the device stacks.  
//
//      Irp: Pointer to an IRP allocated by the caller.
//
//      Urb: Pointer to an URB that is allocated by  USBD_UrbAllocate,
//           USBD_IsochUrbAllocate, USBD_SelectConfigUrbAllocateAndBuild,
//           or USBD_SelectInterfaceUrbAllocateAndBuild.//      CompletionRoutine: Completion routine.
//
// Return Value:
//
//      NTSTATUS  NTSTATUS SubmitUrbSync( PDEVICE_EXTENSION DeviceExtension,PIRP Irp,PURB Urb,  PIO_COMPLETION_ROUTINE SyncCompletionRoutine)  {NTSTATUS  ntStatus;  KEVENT    kEvent;PIO_STACK_LOCATION nextStack;// Get the next stack location.nextStack = IoGetNextIrpStackLocation(Irp);  // Set the major code.nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;  // Set the IOCTL code for URB submission.nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;  // Attach the URB to this IRP.// The URB must be allocated by USBD_UrbAllocate, USBD_IsochUrbAllocate,// USBD_SelectConfigUrbAllocateAndBuild, or USBD_SelectInterfaceUrbAllocateAndBuild.USBD_AssignUrbToIoStackLocation (DeviceExtension->UsbdHandle, nextStack, Urb);KeInitializeEvent(&kEvent, NotificationEvent, FALSE);ntStatus = IoSetCompletionRoutineEx ( DeviceExtension->NextDeviceObject,  Irp,  SyncCompletionRoutine,  (PVOID) &kEvent,  TRUE,TRUE,TRUE);if (!NT_SUCCESS(ntStatus)){KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "IoSetCompletionRoutineEx failed. \n" ));goto Exit;}ntStatus = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);  if (ntStatus == STATUS_PENDING){KeWaitForSingleObject ( &kEvent,Executive,KernelMode,FALSE,NULL);}ntStatus = Irp->IoStatus.Status;Exit:if (!NT_SUCCESS(ntStatus)){// We hit a failure condition,// We will free the IRPIoFreeIrp(Irp);Irp = NULL;}return ntStatus;
}// The SyncCompletionRoutine routine is the completion routine
// for the synchronous URB submit request.
//
// Parameters:
//
//      DeviceObject: Pointer to the device object.
//      Irp:          Pointer to an I/O Request Packet.
//      CompletionContext: Context for the completion routine.
//
// Return Value:
//
//      NTSTATUS  NTSTATUS SyncCompletionRoutine ( PDEVICE_OBJECT DeviceObject,PIRP           Irp,PVOID          Context)
{PKEVENT kevent;kevent = (PKEVENT) Context;if (Irp->PendingReturned == TRUE){KeSetEvent(kevent, IO_NO_INCREMENT, FALSE);}KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Request completed. \n" ));return STATUS_MORE_PROCESSING_REQUIRED;
}

USB 异步提交
以下示例演示如何异步提交 URB。

// The SubmitUrbASync routine submits an URB asynchronously.
//
// Parameters:
//
// Parameters:
//      DeviceExtension: Pointer to the caller's device extension. The
//                       device extension must have a pointer to
//                       the next lower device object in the device stacks.  
//
//      Irp: Pointer to an IRP allocated by the caller.
//
//      Urb: Pointer to an URB that is allocated by  USBD_UrbAllocate,
//           USBD_IsochUrbAllocate, USBD_SelectConfigUrbAllocateAndBuild,
//           or USBD_SelectInterfaceUrbAllocateAndBuild.//      CompletionRoutine: Completion routine.
//
//      CompletionContext: Context for the completion routine.
//
//
// Return Value:
//
//      NTSTATUSNTSTATUS SubmitUrbASync ( PDEVICE_EXTENSION DeviceExtension,PIRP Irp,PURB Urb,  PIO_COMPLETION_ROUTINE CompletionRoutine,  PVOID CompletionContext)  
{// Completion routine is required if the URB is submitted asynchronously.// The caller's completion routine releases the IRP when it completes.NTSTATUS ntStatus = -1;  PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);  // Attach the URB to this IRP.nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;  // Attach the URB to this IRP.nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;  // Attach the URB to this IRP.(void) USBD_AssignUrbToIoStackLocation (DeviceExtension->UsbdHandle, nextStack, Urb);  // Caller's completion routine will free the irp when it completes.ntStatus = IoSetCompletionRoutineEx ( DeviceExtension->NextDeviceObject,Irp,  CompletionRoutine,  CompletionContext,  TRUE,TRUE,TRUE);if (!NT_SUCCESS(ntStatus)){goto Exit;}(void) IoCallDriver(DeviceExtension->NextDeviceObject, Irp);Exit:if (!NT_SUCCESS(ntStatus)){// We hit a failure condition,// We will free the IRPIoFreeIrp(Irp);Irp = NULL;}return ntStatus;
}

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

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

相关文章

ctfshow-web入门-命令执行(web75-web77)

目录 1、web75 2、web76 3、web77 1、web75 使用 glob 协议绕过 open_basedir&#xff0c;读取根目录下的文件&#xff0c;payload&#xff1a; c?><?php $anew DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString(). ); } ex…

读书笔记-Java并发编程的艺术-第3章(Java内存模型)-第9节(Java内存模型综述)

3.9 Java内存模型综述 前面对Java内存模型的基础知识和内存模型的具体实现进行了说明。下面对Java内存模型的相关知识做一个总结。 3.9.1 处理器的内存模型 顺序一致性内存模型是一个理论参考模型&#xff0c;JMM和处理器内存模型在设计时通常会以顺序一致性内存模型为参照。…

ORB-SLAM2 安装编译运行(非 ROS)

安装编译 必备安装工具 主要包括 cmake 、 git 、 gcc 、 g gcc 的全称是 GNU Compiler Collection&#xff0c;它是由 GNU 推出的一款功能强大的、性能优越的 多平台编译器&#xff0c;是一个能够编译多种语言的编译器。最开始 gcc 是作为 C 语言的编译器&#xff08;GNU …

如何将等保2.0的要求融入日常安全运维实践中?

等保2.0的基本要求 等保2.0是中国网络安全领域的基本国策和基本制度&#xff0c;它要求网络运营商按照网络安全等级保护制度的要求&#xff0c;履行相关的安全保护义务。等保2.0的实施得到了《中华人民共和国网络安全法》等法律法规的支持&#xff0c;要求相关行业和单位必须按…

C#/WPF 自制白板工具

随着电子屏幕技术的发展&#xff0c;普通的黑板已不再适用现在的教学和演示环境&#xff0c;电子白板应运而生。本篇使用WPF开发了一个电子白板工具&#xff0c;功能丰富&#xff0c;非常使用日常免费使用&#xff0c;或者进行再次开发。 示例代码如下&#xff1a; Stack<St…

拓扑排序[讲课留档]

拓扑排序 拓扑排序要解决的问题是给一个有向无环图的所有节点排序。 即在 A O E AOE AOE网中找关键路径。 前置芝士&#xff01; 有向图&#xff1a;有向图中的每一个边都是有向边&#xff0c;即其中的每一个元素都是有序二元组。在一条有向边 ( u , v ) (u,v) (u,v)中&…

JavaScript 动态网页实例 —— 广告效果

广告是现代网页设计中不可或缺的内容。广告可以有很多种形式,但最终目的都是要吸引观众的注意力。尽管广告少不了画面、音效和广告语等效果,但其实现主要还是应用JavaScript 代码,只要很好掌握了JavaScript程序设计,剩下的就是创意和美工了。本章介绍几种广告效果,包括对联…

ChatGPT 官方发布桌面端,向所有用户免费开放

Open AI 官方已经发布了适用于 macOS 的 ChatGPT 桌面端应用。 此前&#xff0c;该应用一直处于测试阶段&#xff0c;仅 Plus 付费订阅用户可以使用。 目前已面向所有用户开放&#xff0c;所有 Mac 用户均可免费下载使用。 我们可以访问官网下载安装包&#xff1a;https://op…

Java利用poi实现word,excel,ppt,pdf等各类型文档密码检测

介绍 最近工作上需要对word,excel,ppt,pdf等各类型文档密码检测&#xff0c;对文件进行分类&#xff0c;有密码的和没密码的做区分。查了一堆资料和GPT都不是很满意&#xff0c;最后东拼西凑搞了个相对全面的检测工具代码类&#xff0c;希望能给需要的人带来帮助。 说明 这段…

PHP 爬虫之使用 Curl库抓取淘宝商品列表数据网页的方法

使用 PHP 的 cURL 库来抓取淘宝商品列表数据网页需要谨慎&#xff0c;因为淘宝等电商平台通常会有反爬虫机制&#xff0c;以防止数据被滥用。然而&#xff0c;如果你只是出于学习目的&#xff0c;并且了解并遵守了淘宝的robots.txt文件和相关的使用条款&#xff0c;你可以尝试使…

2024 年江西省研究生数学建模竞赛题目 B题投标中的竞争策略问题--完整思路、代码结果分享(仅供学习)

招投标问题是企业运营过程中必须面对的基本问题之一。现有的招投标平台有国家级的&#xff0c;也有地方性的。在招投标过程中&#xff0c;企业需要全面了解招标公告中的相关信息&#xff0c;在遵守招投标各种规范和制度的基础上&#xff0c;选择有效的竞争策略和技巧&#xff0…

基于JSP技术的校园餐厅管理系统

开头语&#xff1a; 你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果您对校园餐厅管理系统感兴趣或有相关需求&#xff0c;欢迎随时联系我。我的联系方式在文末&#xff0c;期待与您交流&#xff01; 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#x…

QT的编译过程

qmake -project 用于从源代码生成项目文件&#xff0c;qmake 用于从项目文件生成 Makefile&#xff0c;而 make 用于根据 Makefile 构建项目。 详细解释&#xff1a; qmake -project 这个命令用于从源代码目录生成一个初始的 Qt 项目文件&#xff08;.pro 文件&#xff09;。它…

Keil5中:出现:failed to execute ‘...\ARMCC\bin\ArmCC‘

点三个点&#xff0c;去自己的磁盘找自己的ARM\ARMCC\bin

深入解析:计算机系统总线全方位解读

在计算机组成原理中&#xff0c;总线系统是连接计算机各个部件的重要通道。本文将详细介绍系统总线的基本概念、分类、特性及性能指标、结构和控制方式。希望通过本文的讲解&#xff0c;能够帮助基础小白更好地理解计算机系统总线的工作原理。 系统总线 (System Bus) 系统总线…

查看视频时间基 time_base

时间基、codec, 分辨率&#xff0c;音频和视频的都一样&#xff0c;才可以直接使用ffmpeg -f concat -i file.txt 方式合并。 On Thu, Dec 03, 2015 at 21:54:53 0200, redneb8888 wrote: I am looking for a way to find the time base of a stream (video or audio), $ ffpr…

selenium 简介以及 selenium 环境配置

文章目录 一、初识 selenium1.selenium 简介2.selenium 三大组件3.selenium工作过程和原理4.selenium自动化测试流程5.selenium优点 二、自动化测试1.UI自动化本质2.UI自动化的前提3.适用场景4.UI自动化的原则5.UI自动化的覆盖率 三、selenium 环境配置 一、初识 selenium 1.s…

单点登录demo

gitee.com 搜索xxl(许雪里) 的sso 操作demo 完整流程图

网络安全控制相关技术

1.恶意代码&#xff08;Malware&#xff09; 网络从出现、发展演进都始终伴随着安全方面的问题&#xff0c;只是每个阶段表现的形式不同而已。在网络安全方面&#xff0c;不能不提进行网络攻击的网络病毒&#xff0c;或者说恶意代码&#xff08;Malware&#xff09;。所有恶意…

MySQL中的网络命名空间支持

Network Namespace Support&#xff08;网络命名空间支持&#xff09; 提供了在Linux系统中创建和管理多个隔离网络空间的能力。网络命名空间是来自主机系统的网络堆栈的逻辑副本。网络命名空间对于设置容器或虚拟环境非常有用。每个名称空间都有自己的IP地址、网络接口、路由表…