热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

USB协议整理三:USB概述及协议基础(二)

八、USB的描述符及其之间的关系详细内容见《USB2.0协议》9.6StandardUSBDescriptorDefinitions章节。1、设备描述符说明:翻

八、USB 的描述符及其之间的关系

详细内容见《USB2.0协议》9.6 Standard USB Descriptor Definitions 章节。
在这里插入图片描述


1、设备描述符

说明:翻译《USB2.0 标准协议》9.6.1 Device 章节。

设备描述符描述有关 USB 设备的一般信息。它包括全局应用于设备和设备的所有配置的信息一个 USB 设备只有一个设备描述符

具有高速能力的设备,如果设备信息全速高速不同,则必须有一个设备限定符描述符(device_qualifier)(参见章节9.6.2)。

具有高速能力的设备的 DEVICE 描述符的版本号是2.0 (0200H)。如果设备仅全速或仅低速,则此版本号表示它将正确响应对设备限定符描述符(device_qualifier)执行器的请求(即,它将以请求错误进行响应)。

bcdUSB 字段包含 BCD 版本号。对于JJ.M.N版本,bcdUSB字段的值是0xJJMN (JJ主版本号,M次版本号,N次次版本号),例如,版本2.1.3用值0x0213表示,版本2.0用值0x0200表示。

bNumConfigurations字段表示当前运行速度下的配置数量。其他运行速度的配置不包括在计数中。如果设备针对特定速度进行了特定配置,则 bNumConfigurations 字段仅反映单个速度的配置数,而不是两种速度的配置总数。

如果设备高速运行,则 bMaxPacketSize0 字段必须为 64,表示最大数据包数为 64 字节。高速操作不允许控制端点(端点0)的其他最大数据包大小。

所有USB设备都有一个默认控制管道。设备描述符中描述了设备的默认控制管道的最大数据包大小。特定于配置及其接口的端点在配置描述符中进行描述。配置及其接口不包含默认控制管道的端点描述符。除了最大数据包大小之外,默认控制管道的特征由本规范定义,并且对所有USB设备都是相同的。

bNumConfigurations字段标识设备支持的配置的数量。表 9-8 显示了标准设备描述符
在这里插入图片描述
在这里插入图片描述


偏移量大小描述
0bLength1Number此描述符的大小(以字节为单位)
1bDescriptorType1Constant设备描述符类型。此字段标识设备及其描述符所遵循的 USB 规范的版本。
2bcdUSB2BCD以二进制编码的十进制表示的 USB 规范发布号(即 2.10 为 210H)。此字段标识设备及其描述符所遵循的 USB 规范的版本。
4bDeviceClass1Class类代码(由 USB-IF 分配)。如果该字段被重置为零,则配置中的每个接口指定自己的类信息,并且各个接口独立运行。如果此字段设置为介于 1 和 FEH 之间的值,则器件在不同接口上支持不同的类规范,并且接口可能无法独立运行。此值标识用于聚合接口的类定义。如果此字段设置为 FFH,则设备类是特定于供应商的。
5bDeviceSubClass1SubClass子类代码(由 USB-IF 分配)。这些代码由 bDeviceClass 字段的值限定。如果 bDeviceClass 字段重置为零,则此字段也必须重置为零。如果 bDeviceClass 字段未设置为 FFH,则保留所有值以供 USB-IF 分配。
6bDeviceProtocol1Protocol协议代码(由USB-IF分配)。这些代码由 bDeviceClass 和 bDeviceSubClass 字段的值限定。如果设备支持基于设备的类特定协议,而不是基于接口的协议,则此代码标识设备使用的协议,该协议由设备类规范定义。如果该字段被重置为零,则表示设备不使用基于设备的类特定协议。然而,它可以在接口的基础上使用类特定的协议。如果此字段设置为 FFH,则设备将基于设备使用特定于供应商的协议。
7bMaxPacketSize01Number端点零的最大数据包大小(只有 8、16、32 或 64 有效)。
8idVendor2ID供应商 ID(由 USB-IF 分配)。
10idProduct2ID产品 ID(由制造商分配)。
12bcdDevice2BCD以二进制编码的十进制表示的设备版本号。
14iManufacturer1Index描述制造商的字符串描述符索引。
15iProduct1Index描述产品的字符串描述符的索引。
16iSerialNumber1Index描述设备序列号的字符串描述符的索引。
17bNumConfigurations1Number可能的配置数量。

2、设备限定符

说明:翻译《USB2.0 标准协议》9.6.2 Device_Qualifier 章节。

设备限定符描述了有关高速设备的信息,如果设备以另一种速度运行,这些信息就会改变。例如,如果设备当前正在全速运行,设备限定符将返回关于它如何在高速运行的信息,反之亦然。表9-9显示了设备限定符描述符的字段
在这里插入图片描述


偏移量大小描述
0bLength1Number描述符的大小
1bDescriptorType1Constant设备限定符类型
2bcdUSB2BCDUSB 规范版本号(例如,V2.00 为 0200H)
4bDeviceClass1Class类代码
5bDeviceSubClass1SubClass子类代码
6bDeviceProtocol1Protocol协议代码
7bMaxPacketSize01Number其他速度的最大包大小
8bNumConfigurations1Number其他速度配置的数量
9bReserved1Zero保留以后使用,必须为零

标准设备描述符供应商产品设备制造商产品序列号字段不包括在此描述符中,因为对于所有受支持的速度,该信息对于设备都是常量的。此描述符的版本号必须至少为 2.0 (0200H)

主机使用 GetDescriptor() 请求访问此描述符。GetDescriptor()请求中的描述符类型被设置为设备限定符(见表9-5)。

如果一个全速度的设备(设备描述符版本号等于0200H)接收到一个设备限定符的GetDescriptor()请求,它必须响应一个请求错误。除非首先成功检索到设备限定符描述符,否则主机不能请求其他速度配置描述符。


3、配置描述符

说明:翻译《USB2.0 标准协议》9.6.3 Configuration 章节。

配置描述符描述有关特定设备配置的信息。描述符包含一个bConfigurationValue字段,该字段的值用作SetConfiguration()请求的参数时,该值会导致设备采用所描述的配置。

描述符描述配置提供的接口数。每个接口可以独立运行。例如,ISDN 设备可能配置了两个接口,每个接口提供 64 Kb/s 的双向通道,这些通道在主机上具有单独的数据源或接收器。另一种配置可能会将 ISDN 设备显示为单个接口,将两个通道绑定到一个 128 Kb/s 的双向通道中。

当主机请求配置描述符时,将返回所有相关的接口和端点描述符(请参见第 9.4.3 节)。

USB 设备具有一个或多个配置描述符每个配置都有一个或多个接口,每个接口都有零个或多个端点。一个端点不能在单个配置中的接口之间共享,除非同一接口的其他设置使用该端点。在没有这个限制的情况下,可以在不同配置的接口之间共享端点。

一旦配置完成,设备可能支持对配置进行有限的调整。如果某个接口有可选的设置,则可在配置后选择可选的。表 9-10 显示了标准配置描述符
在这里插入图片描述
在这里插入图片描述


偏移量大小描述
0bLength1Number此描述符的大小(以字节为单位)
1bDescriptorType1Constant配置描述符类型
2wTotalLength2Number此配置返回的数据的总长度。包含此配置返回的所有描述符(配置、接口、端点和特定于类或供应商的)的组合长度。
4bNumInterfaces1Number此配置支持的接口数
5bConfigurationValue1Number用作 SetConfiguration() 请求的参数以选择此配置的值
6iConfiguration1Index描述此配置的字符串描述符的索引
7bmAttributes1Bitmap配置特性:D7:保留(设置为 1)D6:自供电的D5:远程唤醒D4~0:保留(重置为零)D7 是保留的,由于历史原因,必须设置为 1。使用来自总线和本地电源的设备配置以 bMaxPower 为单位报告非零值,以指示所需的总线功率量并设置 D6。运行时的实际电源可以通过GetStatus(DEVICE)请求来确定(参见9.4.5节)。如果设备配置支持远程唤醒,则 D5 将设置为 1。
8bMaxPower1mA当设备完全运行时,USB设备在此特定配置下从总线获得的最大功耗。以 2 mA 单位表示(即 50 = 100 mA)。注意:设备配置报告配置是总线供电还是自供电。设备状态报告设备当前是否自供电。当设备与外部电源断开连接时,会更新设备状态,表示设备已不再自供电。当设备失去外部电源时,如果超出其配置报告的量,则设备可能不会增加其从总线的功耗。如果设备在与其外部电源断开连接时可以继续运行,则设备将继续运行。如果设备无法继续运行,则操作将失败,无法再支持。USB 系统软件可以通过检查状态并注意设备电源的丢失来确定故障原因。

4、其他速度配置

说明:翻译《USB2.0 标准协议》9.6.4 Other_Speed_Configuration 章节。

表9-11中显示的另一个速度配置描述符描述了高速设备的配置,如果它在其他可能的速度下运行。另一个速度配置的结构与配置描述符相同。
在这里插入图片描述


偏移量大小描述
0bLength1Number描述符的大小
1bDescriptorType1Constant其他速率配置类型
2wTotalLength2Number返回的数据总长度
4bNumInterfaces1Number此速度配置支持的接口数
5bConfigurationValue1Number用于选择配置的值
6iConfiguration1Index字符串描述符索引
7bmAttributes1Bitmap与配置描述符相同
8bMaxPower1mA与配置描述符相同

主机使用GetDescriptor()请求访问这个描述符。GetDescriptor()请求中的描述符类型被设置为其他速度配置(见表9-5)。


5、接口描述符

说明:翻译《USB2.0 标准协议》9.6.5 Interface 章节。

接口描述符描述配置中的特定接口。配置提供一个或多个接口,每个接口都有零个或多个端点描述符,描述配置中一组唯一的端点。当一个配置支持多个接口时,特定接口的端点描述符在GetConfiguration()请求返回的数据中的接口描述符后面。接口描述符总是作为配置描述符的一部分返回。接口描述符不能通过GetDescriptor()或SetDescriptor()请求直接访问。

一个接口可以包括备用设置,允许端点和或它们的特征在设备配置后发生变化。接口的默认设置始终为备用设置零。SetInterface()请求用于选择备用设置或返回默认设置。GetInterface()请求返回所选的备用设置。

备用设置允许设备配置的一部分发生变化,而其他接口仍在运行。如果一个配置对它的一个或多个接口有备用设置,则每个设置包含一个单独的接口描述符及其关联的端点。

如果设备配置支持具有两个备选设置的单个接口,则配置描述符后面将跟着一个接口描述符,该接口描述符的bInterfaceNumber和balternatessetting字段设置为0,然后是该设置的端点描述符,后面是另一个接口描述符及其关联的端点描述符。第二个接口描述符的bInterfaceNumber字段也将被设置为0,但是第二个接口描述符的balternatessetting字段将被设置为1。

如果接口只使用端点0,则接口描述符后面没有端点描述符。在这种情况下,bNumEndpoints字段必须设置为0。

接口描述符永远不会在端点的数量中包含端点0。标准接口描述符如表9-12所示
在这里插入图片描述
在这里插入图片描述


偏移量大小描述
0bLength1Number此描述符的大小(以字节为单位)
1bDescriptorType1Constant接口描述符类型
2bInterfaceNumber1Number此接口的编号。从零开始的值标识此配置支持的并发接口数组中的索引。
3bAlternateSetting1Number用于为上一字段中标识的接口选择此备用设置的值
4bNumEndpoints1Number该接口使用的端点数(不包括端点0)。如果该值为0,则该接口只使用默认控制管道。
5bInterfaceClass1Class类代码(由 USB-IF 分配)。值0保留为将来的标准化使用。如果该字段设置为FFH,则接口类是特定于供应商的。所有其他值都保留给USB-IF分配。
6bInterfaceSubClass1SubClass子类代码(由 USB-IF 分配)。这些代码由 bInterfaceClass 字段的值限定。如果 bInterfaceClass 字段重置为零,则此字段也必须重置为零。如果 bInterfaceClass 字段未设置为 FFH,则所有值都将保留以供 USB-IF 分配。
7bInterfaceProtocol1Protocol协议代码(由 USB 分配)。这些代码由 bInterfaceClass 和 bInterfaceSubClass 字段的值限定。如果接口支持类特定的请求,此代码将识别设备使用的协议,该协议由设备类规范定义。如果该字段被重置为0,表示该接口不使用类特定的协议。当该字段设置为FFH时,表示设备在该接口上使用特定于厂商的协议。
8iInterface1Index描述此接口的字符串描述符的索引

6、端点描述符

说明:翻译《USB2.0 标准协议》9.6.6 Endpoint 章节。

用于接口的每个端点都有自己的描述符。这个描述符包含主机确定每个端点的带宽需求所需的信息。端点描述符总是作为GetDescriptor(configuration)请求返回的配置信息的一部分返回。端点描述符不能通过GetDescriptor()或SetDescriptor()请求直接访问。端点0没有端点描述符。表9-13给出了标准端点描述符
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


偏移量大小描述
0bLength1Number此描述符的大小(以字节为单位)
1bDescriptorType1Constant端点描述符类型
2bEndpointAddress1Endpoint此描述符描述的USB设备上端点的地址。地址编码如下:Bit 3…0:端点数量Bit 6…4:保留,重置为零BIt 7:方向,控制端点忽略(0-输出端点、1-输入端点)
3bmAttributes1Bitmap当使用bConfigurationValue配置端点时,该字段描述端点的属性。Bits 1…0:传输类型(00-控制传输、01-同步传输、10-批传输、11-中断传输)如果不是一个同步端点,Bit5…2是保留的,必须设置为零。如果是同步传输的,则定义如下:Bits 3…2:同步类型(00-无同步、01-异步、10-自适应、11-同步)Bits 5…4:使用类型(00-数据端点、01-反馈端点、10-隐式反馈数据端点、11-保留)更多信息请参阅第5章。所有其他位都保留,必须重置为零。保留位必须被主机忽略。
4wMaxPacketSize2Number选择此配置时,此端点能够发送或接收的最大包大小。对于同步端点,这个值用于在调度中保留总线时间,每(微)帧数据有效负载所需的时间。管道实际使用的带宽可能比保留的带宽要少。如有必要,设备通过其正常的非 USB 定义机制报告实际使用的带宽。对于所有端点,Bit10…0表示最大报文大小(以字节为单位)。用于高速同步和中断端点:Bit12…11 指定每个微帧的额外事务机会数(00-无(每微帧1个事务)、01-1 个附加(每个微帧 2 个)、10-2 个附加(每个微帧 3 个)、11-保留)Bits 15…13:保留的,必须设置为零。更多信息请参阅第5章。
6bInterval1Number数据传输的轮询端点的间隔。根据设备的运行速度(即1毫秒或125秒单位),以帧或微帧表示。对于全速/高速常时等量端点,此值必须在 1 到 16 的范围内。bInterval值用作2的bInterval-1次方;例如,bInterval为4表示周期为8(2的4-1次方)。对于全速/低速中断端点,此字段的值可能介于 1 到 255 之间。对于高速中断端点,bInterval值被用作2的bInterval-1次方;例如,bInterval为4表示周期为8(2的4-1次方)。取值范围为1 ~ 16。对于高速批量/控制 OUT 端点,bInterval 必须指定端点的最大 NAK 速率。值为 0 表示终结点从不进行 NAK。其他值表示微帧的每个bInterval数量最多为1个NAK。取值范围为0 ~ 255。请参阅第5章对周期的详细描述。

battributes字段提供了端点的传输类型(Bit 1…0)和同步类型(Bit 3…2)的信息。此外,使用类型位(Bit5…4)指出这是否是用于正常数据传输的端点(Bit 5…4=00B),它是用于传递一个或多个数据端点(Bit 5…4=01B)的显式反馈信息,还是作为一个或多个数据端点(Bit 5…4=10B)的隐式反馈端点的数据端点。Bit5 . .2只对同步端点有意义,对于所有其他传输类型必须重置为零。

如果端点被用作显式反馈端点(Bit 5…4=01B),那么传输类型必须设置为同步(Bit 1…0 = 01B),同步类型必须设置为不同步(Bit 3…2=00B)。

反馈端点(显式或隐式)需要与一个(或多个)向其提供反馈服务的同步数据端点相关联。关联基于端点号匹配。反馈端点总是具有与它服务的数据端点相反的方向。如果多个数据端点要由同一个反馈端点提供服务,那么数据端点必须具有升序的但不一定是连续的端点编号。第一个数据端点和反馈端点必须具有相同的端点号(和相反的方向)。这确保数据端点可以唯一地标识其反馈端点,方法是搜索端点编号等于或小于其自己端点编号的第一个反馈端点。

例如:考虑极端情况,需要5组OUT异步等时端点,同时需要4组IN自适应等时端点。每组需要一个独立的反馈端点,如图9-7所示。
在这里插入图片描述
高速同步和中断终端使用wMaxPacketSize的 Bit 12…11 来为每个由bInterval指定的微帧指定多个事务。如果wMaxPacketSize的 Bit 12…11 为零,端点的最大数据包大小可以是任何允许的值(如第五章所定义)。如果wMaxPacketSize的 Bit 12…11 不为0,则限制wMaxPacketSize的 Bit 10…0,如表9-14所示。
在这里插入图片描述
对于高速批量和控制 OUT 端点,bInterval 字段仅用于合规性目的;主控制器不需要根据该字段的值改变其行为。


7、字符串

说明:翻译《USB2.0 标准协议》9.6.7 String 章节。

字符串描述符是可选的。如前所述,如果设备不支持字符串描述符,则设备、配置和接口描述符内对字符串描述符的所有引用必须重置为0。

字符串描述符使用的 UNICODE 编码。USB设备中的字符串可能支持多种语言。当请求字符串描述符时,请求者使用USB-IF定义的16位语言ID (LANGID)指定所需的语言。当前定义的 USB LANGID 列表可在 http://www.usb.org/developers/docs.html 中找到。所有语言的字符串索引0都返回一个字符串描述符,该描述符包含设备支持的两字节LANGID代码数组。表 9-15 显示了 LANGID 代码数组。USB 设备可能会省略所有字符串描述符。省略所有字符串描述符的 USB 设备不得返回 LANGID 代码数组。

LANGID 代码数组不是 NULL 终止的。数组的大小(以字节为单位)是通过从描述符的第一个字节的值中减去 2 来计算的。
在这里插入图片描述


偏移量大小描述
0bLength1N+2此描述符的大小(以字节为单位)
1bDescriptorType1Constant字符串描述符类型
2wLANGID[0]2NumberLANGID 代码 0
…………………………
NwLANGID[x]2NumberLANGID 代码 x

UNICODE 字符串描述符(如表 9-16 所示)不是以 NULL 终止的。字符串长度是通过从描述符的第一个字节的值中减去 2 来计算的。
在这里插入图片描述


偏移量大小描述
0bLength1Number此描述符的大小(以字节为单位)
1bDescriptorType1Constant字符串描述符类型
2bString1NumberUNICODE编码的字符串

8、对于各个字段说明

参考《USB2.0》11.23.1 Standard Descriptors for Hub Class 章节。


推荐阅读
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
author-avatar
林林-007
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有