完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
6个回答
|
|
初识USB
USB是一种串行接口协议,它靠D+、D-两条数据线构成的差分线来进行数据传输,这让我们非常感兴趣,它到底和我们通常熟悉两线RS232/485有何区别。了解这种区别有助于我们对USB作一个深入的了解。那么让我们回想一下到底一个两线RS232的数据是如何传送的,如图一: 在这里我们的重点在于,我们发现要在串行口传送数据一个最体码的要求恐怕就是:要知道数据传输何时开始,何时结束,即如何delimit。 那么RS232怎么做的? 显然,在IDLE(空闲)时,即无数据传送时,数据线处于高电平,等到有数据开始传送,发送方首先拉低数据线(start),表示数据传输开始,接受端也因为这个start信号开始准备接受即将到来的数据,类似一次握手。随后,在两者之间的数据传送开始,结束后主方再次拉高数据线,表示结束传输,自此两者重新进入IDLE状态,等待下一轮传送开始。 了解了RS232,那么我们自然想到USB如何做到这个呢?既然是串行位流传输,也理所当然的解决这个问题。 没错,USB协议必然要解决这个问题,让我们作一个类似RS232的比较吧!类似于RS232,USB的传输桢如图二: (这里我们暂时忽略这个传输所代表的意义)为了说明问题,我们对一些问题简化,我们定义这样几个状态: 假设D+、D-分别表示USB信号线的电平信号。那么对于USB full speed function(high speed、low speed是不同的),我们定义差分数据线上可能出现的四个状态: Data J state: D+ = 1,D- = 0; Data K state: D+ = 0,D- = 1; SE0: D+ = D- = 0; SE1: D+ = D- = 1。 那么上面的图中,相应的也可表示为图三: 这个对USB full speed function来说,IDLE状态将处于Data J state,SE0表示一桢结束。看这个图是不是很像我们熟悉的RS232。没错!!!他们确实很相似。在无数据传输时,它们都处于IDLE状态,当要开始传输数据时,先发一个SYNC(同步信号,RS232为start,USB为一SYNC字节,见协议说明)信号进行“握手”,而后开始传输,当传输要结束时,发一STOP信号(USB为一个SE0状态表示要结束传输),最后又进入IDLE态等待新的传输。 不过,你可能更加注意到,他们还是不同的。不同在于USB是按packet进行传输的,就是说它传输的最小单位是packet,而RS232是按字节传送的,也即它的最小传送单位是字节。既然是按pakcet传送,想想我们相较于RS232的按字节单位传输,我们可以得到哪些“好处”。 想想看,pakcet的好处不就在于我们可以灵活的定义数据的传送格式,传送方式,从而可以适应各种各样的串行设备,这不就是所谓的“通用串行总线(USB)”吗? |
|
|
|
USB传输方式——非对称传输
简介:本小节将介绍USB的传输机制。这节先介绍USB现有传输方式的背景知识,做为对下节将要展开的四种传输类型,描述符,等相关知识的一个导引。 我们在上一节中了解到了USB的packet的感念,了解到了USB传送一个packet总是以SYNC开始,以EOP结束,这个称为delimiter,即标记packet的始末。有了packet,我们就可以在USB总线上传输数据了。但是这还不够。 比如数据传送方向,即传回USB主机还是传下USB从机,数据传送的地址,数据传送的类型(这些后面我们将会知道)这些信息在传输之前是必须搞清楚的,那么这个信息如何得知呢,看来这就需要我们定一套基于packet的“协议”了。主机与从机在传输中均遵循这套“协议”,那么这些问题就可以迎刃而解。 事实上,USB的一次数据传输总是遵循这样的“协议”的: 首先,主机发第1个packet给从机,声明数据传送方向,数据传输地址,数据传输类型; 其次,主机发第2个至第n个packet载有实际数据; 最后,从机返回一个packet是一个ACK包,报告数据传输的结果,比如接受出错或成功等信息,这样主机,就可以借此了解到这次传输情况,从而有可能来作出相应措施如决定是否重发。 这里我们考虑的是主机发数据给从机的情况,那么从机发数据给主机时,是不是也可以这样呢?当然可以,比如从机要发数据给主机时,也可以采取同主机类似的方式: 首先,从机发第1个packet给主机,声明数据传送方向,数据传输地址,数据传输类型; 其次,从机发第2个至第n个packet载有实际数据; 最后,主机返回一个packet是一个ACK包,报告数据传输的结果,比如接受出错或成功等信息,这样从机就可以借此了解到这次传输情况,从而有可能来作出相应措施如决定是否重发。 基本上可以归结为一个“三段式”传输。 这里有人可能注意到了,对这样一个传输机制,从机和主机的功能将是一样的,因为这样的实现机制,从机可能在某一时刻是主机,某一时刻又可能是从机,因为他们要实现同样的功能。这样实现起来的复杂性也将是一样的。 注:这里概念或许容易混淆,其实,我们这里的主机(master)和从机(slaver)是一个transceiver,即可收可发。相应的,在某一时刻,master在发数据,我们称其为transmitter,在接受时我们称为receiver。对slaver同样。 我们可能还注意到了,USB这种按pakcet传输的方式在实现时已经很复杂了(至少比RS232要复杂多吧),至少我们目前看来主从机功能一样这样的实现方式似乎还是可行,但是后面我们谈到USB host时将会了解到host的功能是如何的复杂,以至于让一个USB function 也带上如此的功能成本和实现复杂性将陡然上升。作为面向广范应用的USB,这是我们不允许的。我们期望的是一个使用USB 的udisk,使用USB的光驱,使用USB的耳麦等等这些东西不要因为USB而变得昂贵,复杂。 正是因为这个原因,USB从机的传输发式便由上面的方式改成了下面的方式进行: 首先,主机发第1个packet给从机,声明数据传送方向,数据传输地址,数据传输类型; 其次,从机收到主机送来的第一个packet后,再发第2个至第n个packet载有实际数据; 最后,主机返回一个packet是一个ACK包,报告数据传输的结果,比如接受出错或成功等信息,这样从机就可以借此了解到这次传输情况,从而有可能来作出相应措施如决定是否重发。 而对于USB 主机传输方式保持不变。 对于这样的改变,我们马上就有疑问了:这个改变的传输方式是和未改变之前的等价吗。当然,不全等价。问题在哪里?仔细观察一下便知,两者区别在于第一个packet是由谁发起的。 未改变之前,第一个packet总是由要传送数据的一方发起,而改变之后的第一个Packet总是由主机发起。这样,就变成如果从机要发送数据给主机时,总是由主机发起(第一个packet),然后从机开始传送。 可能初次接触我们会感觉怪怪的,怎么从机要给主机发送数据前反而要主机先发packet给从机。 这样行吗? 我要说这样是可以的,因为通常一次传输交互的产生,并非无来由的产生,这些都是由程序员控制的,控制USB何时收,何时发,及发给谁!!! 这里我们就注意到了,USB function(总是作为从机)的功能一下从原来与主机具有相同功能的tranceiver变成了现在仅具发送(或接收)功能的transmitter(或Receiver)实现的复杂性及成本可想而知也就相应得减小了。 |
|
|
|
USB的4种传输类型
简介:本节介绍USB full speed function的四种传输类型。 3.1. 控制传输(Control Transfers) 上节中我们了解到了USB host 与USB function 之间采用的是一种“非对称”的传输,也就是说,无论USB接受数据还是发送数据,都是由USB host首先发起。即传输的第一个packet总是由USB host发出的。这个packet将声明本次即将进行的数据传输方向,数据传输地址和数据传输类型。 或许你已经注意到了,一个USB host端口并不是仅仅支持一个USB function,如图: 通过USB hub,一个USB host端口可以连接USB鼠标,USB键盘,USB写字板。..。..。要连接这么多东西在同一个USB host上,我们通常会有一个基本问题,即USB host如何识别这些被连接在它的端口上的设备呢? 正如通常的主从式通讯系统一样,如RS485多机通讯,我们通常是用一个特定的地址标志每一个从设备。对这里的USB,我们采用同样的方法,将为每个挂接在该USB host上的USB function指定一个特定地址,通过这个特定地址来识别每个USB function。 看来这将是一个USB function在数据传输之前必须解决的问题——如何得到它的地址分配? 这个“地址指定”的过程需要USB host通知USB function才能完成,这个交互过程就是一个“控制式传输”。 通过这个“控制式传输”,USB host将指定地址给USB function,以为即将进行的正式通讯做好准备工作。这里细心的读者可能已经注意到了,既然USB host总要分配地址给USB function才能进行正式的数据传输工作,那么USB host将如何与一个初始时未分配地址的USB function进行交互来分配地址呢? 这里,是这样解决的: USB协议保留了一个“通用地址0”,USB host通过这个地址0来和初始未分配地址的USB function进行通讯,进行一些初始的准备工作,诸如这里的为它分配一个特定地址。后面我们就会了解到,USB除了配置地址外,还有一些其它参数需要事先主从双方达成共识。这些参数也都是通过控制式传输完成的。 一个USB的“控制式传输”如图: 一个USB的“控制式传输”分为两个或三个阶段进行传输: SETUP stage ——》 DATA stage ——》 STATUS stage 首先是SETUP stage,联系上节所说的USB传输模式,USB Host总是先发起第一个packet:这里它首先发起SETUP,之后发起以DATA0为起始的Setup Data,最后USB function回应ACK结束一次交互。 其次如果有DATA stage,类似的,还是按照上节说的USB传输模式,USB host总是先发起第一个packet:OUT或IN,之后USB host(或USB function)发起以DATA1为起始的Payload Data,最后USB function(或USB host)回应ACK结束一次交互。 如果数据未传完,继续DATA stage,同上继续。 最后是status stage,类似的, USB host首先发起第一个Packet:IN或OUT,之后USB function(或USB host)发起以DATA1为起始的Null Data(0长度),最后USB host(或USB function)回应ACK结束一次交互。 如此,整个控制式传输结束。 你或许有疑问,DATA stage为什么进行了多次而非一次完成? 实际上,USB总是将一批大量的数据分成了许多小段来进行传输,称为一个Payload。这样传输的目的是容易对传输进行控制。既然一次大量的数据总是被分成一段一段来分次传输,那么这里就出现了一个需要事先确定的参数(wMaxPacketSize):即每次即这个小段有多大。这个参数如地址指派一样,正式传输之前需要事先达成共识。 USB host定时对USB集线器的状态进行查询。当一个新USB设备接入集线器时,主机会检测到集线器状态改变,主机发出一个命令使该端口有效并对其进行设置。位于这个端口上的设备进行响应,主机收到关于设备的信息,主机的操作系统确定对这个设备使用那种驱动程序,接着设备被分配一个唯一标识的地址,范围从0~127,其中0为所有的设备在没有分配惟一地址时使用的默认地址。主机向它发出内部设置请求。当一个设备从总线上移走时,主机就从其可用资源列表中将这个设备删除。 通过“控制式传输”,现在我们已经完成了USB function的地址指定等参数的设置工作,下一步可以进行正式的数据传输了。 3.2. 批量传输(Bulk Transactions) 我们终于等到USB function 配置完成,现在我们的任务是要传送一批数据,这里可以使用“批量数据传输(Bulk Transactions)”。 一个“批量传输”总是按照如图所示方式进行: 首先,USB host发起第一个Packet:IN或OUT,表示要开始数据传输了; 其次,USB function(或USB host)发起以DATA1或DATA0为起头的Payload Data,开始一次交互; 最后,USB host(或USB function)发起ACK回应这次交互。 如果数据还未传完,继续上述过程,即: 首先,USB host再次发起一个Packet:IN或OUT,表示又要开始数据传输了; 其次,USB function(或USB host)发起以DATA0或DATA1为起头的Payload Data,开始又一次交互; 再次,USB host(或USB function)发起ACK回应这次交互。 如此继续直至传输完成。 这里的疑问依然是为什么一次可能传完的数据为什么分成多次进行传输,原因在上次介绍“控制式传输”时已经说明。后面我们就会明白,为什么这样可以方便控制传输过程。仔细看看控制式的DATA stage采用的传输方式,是否就是批量传输方式呢?! 注意,每次Payload Data的“牵头人(Preamble)”在轮番掉换,先是DATA1,接着DATA0,再是DATA1.。..。.如此接替,只要有一次交互出现问题,这个接替规则就会被打破进而被USB host识别而发现传输异常。所以这个交替的“牵头人”规则是可靠数据传输的所采取的措施之一。 3.3. 同步(及时)传输(Isochronous Transactions)和中断式传输(Interrupt Transactions) 在“批量数据传输”中,触发一次“批量数据传输”总是“被动”的,就是说需要数据传输时USB host并不会主动发起传输,而是需要得到你的指令。当你告诉它:“一切ok,让我们开始吧!” 这时它才开始数据传输。 这种方式显然在某些情况下并不适合。比如音视频流,你无法要求它听从你的“指挥”,让它等你发指令给USB host,然后开始一次传输。我们需要的是一种“及时的”传输。 一个好的方案就是设置一个Timer,按照Tick发起USB传输。这个Tick通常以1ms(USB full speed)为最小单位。这时,可以设置为每次1ms Tick出现,USB host“自动”发起一次数据传输。那么这种方案具体如何来实现呢? 看来最基本的要素便是一个发出Tick的Timer,而这个Timer需要USB host和USB function(事实上还要包括USB hub)双方均能“看到”,从而协调工作,否则单方面的Timer又有何意义? 这个Timer在USB中使用一个特殊的packet实现,即是SOF。 这个SOF由USB host相当精确地以每1.00ms ±0.0005ms的时间周期发送给USB device(function),来在二者之间定时。从而USB function能够“及时”了解到“现在时刻”。现在我们在USB host和USB function之间建立起了“对时机制”。那么接下来看看刚才设想的“自动”传输如何实现。 事实上,一旦USB host及USB function双方建立了一种时间机制,那么这种“自动”传输是很容易实现的。USB 实现“同步式传输”或“中断式传输”总是以一种类似于“批量数据传输”的方式进行的,唯一不同的是传输的触发不再是被动的,而是由SOF所建立的Tick触发。 首先,Tick时间到达,USB host发起第一个Packet:IN或OUT,表示要开始数据传输了; 其次,USB function(或USB host)发起以DATA1(或DATA0))为起头的Payload Data,开始一次交互; 再次,若是中断式传输,USB host(或USB function)发起ACK回应这次交互,若是同步式传输,该步跳过; 如此重复上述步骤,即USB host等待下一个Tick到达,并开始新一轮的交互。 这里我们注意到了,“同步式传输”和“中断式传输”二者虽然都是时间触发,但是中断式传输需要ACK应答,而“同步式传输”不需要。这个最大的区别决定了“同步式传输”是一种非可靠传输,但是因此换来了更多的USB传输时间。也因此,同步式传输的Payload Data(对应wMaxPacketSize)通常相较于其他传输方式比较大,因为它消掉了ACK所占有数据传输时间。 这里还有一个地方值得注意的是Tick的设定,这个Tick也是需要事先USB host和USB function达成共识的参数之一。 |
|
|
|
USB主机(USB_Host)
USB的所有数据通信(不论是上行通信还是下行通信)都由USB主机启动,所以USB主机在整个数据传输过程中占据着主导地位。在USB系统中只允许有一个主机。从开发人员的角度看,USB主机可分为三个不同的功能模块:客户软件(顶层)、USB系统软件(中层)和USB总线接口(底层)。 4.1. 客户软件 客户软件负责和USB设备的功能单元进行通信,以实现其特定功能。一般由开发人员自行开发。客户软件不能直接访问USB设备,其与USB设备功能单元的通信必须经过USB系统软件和USB总线接口模块才能实现。客户软件一般包括USB设备驱动程序和界面应用程序两部分。 USB设备驱动程序负责和USB系统软件进行通信。通常,它向USB总线驱动程序发出I/O请求包(IRP)以启动一次USB数据传输。此外,根据数据传输的方向,它还应提供一个或空或满的数据缓冲区以存储这些数据。 界面应用程序负责和USB设备驱动程序进行通信,以控制USB设备。它是最上层的软件,只能看到向USB设备发送的原始数据和从USB设备接收的最终数据。 4.2. USB系统软件 USB系统软件负责和USB逻辑设备进行配置通信,并管理客户软件启动的数据传输。USB逻辑设备是程序员与USB设备打交道的部分。USB系统软件一般包括USB总线驱动程序和USB主控制器驱动程序这两部分。这些软件通常由操作系统提供,开发人员不必掌握。 4.3. USB总线接口 USB总线接口包括主控制器和根集线器两部分。根集线器为USB系统提供连接起点,用于给USB系统提供一个或多个连接点(端口)。主控制器负责完成主机和USB设备之间数据的实际传输,包括对传输的数据进行串行编解码、差错控制等。该部分与USB系统软件的接口依赖于主控制器的硬件实现,开发人员不必掌握。 |
|
|
|
USB设备(USB_Device/Function)
5.1. USB设备功能模块 一个USB设备由三个功能模块组成:USB总线接口(底层)、USB逻辑设备(中层)和功能单元(顶层)。 USB总线接口指的是USB设备中的串行接口引擎(SIE); USB逻辑设备被USB系统软件看作是一个端点的集合; 功能单元被客户软件看作是一个接口的集合。 5.2. USB设备架构 为了更好地描述USB设备的特征,USB提出了设备架构的概念。 从这个角度来看,可以认为USB设备是由一些配置、接口和端点组成的,即一个USB设备可以含有一个或多个配置,在每个配置中可含有一个或多个接口,在每个接口中可含有若干个端点。 其中,配置和接口是对USB设备功能的抽象,实际的数据传输由端点来完成。 在使用USB设备前,必须指明其采用的配置和接口。这个步骤一般是在设备接入主机时设备进行自举时完成的,我们在后面会进一步介绍。 USB设备使用各种描述符来说明其设备架构,包括:设备描述符、配置描述符、接口描述符、端点描述符以及字符串描述符,它们通常被保存在USB设备的固件程序中。 5.2.1. 设备 设备代表一个USB设备,它由一个或多个配置组成。设备描述符用于说明设备的总体信息,并指明其所含的配置的个数。一个USB设备只能有一个设备描述符。 5.2.2. 配置 一个USB设备可以包含一个或多个配置,如USB设备的低功耗模式和高功耗模式可分别对应一个配置。在使用USB设备前,必须为其选择一个合适的配置。配置描述符用于说明USB设备中各个配置的特性,如配置所含接口的个数等。USB设备的每一个配置都必须有一个配置描述符。 5.2.3. 接口 一个配置可以包含一个或多个接口,如对一个光驱来说,当用于文件传输时使用其大容量存储接口;而当用于播放CD时,使用其音频接口。接口是端点的集合,可以包含一个或多个可替换设置,用户能够在USB处于配置状态时,改变当前接口所含的个数和特性。接口描述符用于说明USB设备中各个接口的特性,如接口所属的设备类及其子类等。USB设备的每个接口都必须有一个接口描述符。 5.2.4. 端点 端点是USB设备中的实际物理单元,USB数据传输就是在主机和USB设备各个端点之间进行的。 端点一般由USB接口芯片提供,例如Freescale的MC68HC908JB8。 USB设备中的每一个端点都有唯一的端点号,每个端点所支持的数据传输方向一般而言也是确定的:或是输入(IN)或是输出(OUT),也有些芯片提供的端点的数据方向是可以配置的,例如MC68HC908JB8包含有两个用于数据收发的端点:端点1和端点2。其中端点1只能用于数据发送,即支持输入(IN),端点2既能用于数据发送也可用于数据接收,即支持输入(IN)和输出(OUT)操作。 需要注意的是,在这里数据的传输方向是站在主机的立场上来看得。 比如端点1只能发送数据,在主机看来是端点1向主机输入数据,即IN操作;当端点2配置为接收数据时,主机向端点2输出数据,即OUT操作。这一点是初学者比较容易产生混淆的地方。 利用设备地址、端点号和传输方向就可以指定一个端点,并和它进行通信。 0号端点比较特殊,它有数据输入IN和数据输出OUT两个物理单元,且只能支持“控制传输”。 5.2.5. 字符串 在USB设备中通常还含有字符串描述符,以说明一些专用信息,如制造商的名称、设备的序列号等。它的内容以UNICODE的形式给出,且可以被客户软件所读取。 对USB设备来说,字符串描述符是可选的。 5.2.6. 管道 在USB系统结构中,可以认为数据传输是在主机软件(USB系统软件或客户软件)和USB设备的各个端点之间直接进行的,它们之间的连接称为管道。 管道是在USB设备的配置过程中建立的。 管道是对主机和USB设备间通信流的抽象,它表示主机的数据缓冲区和USB设备的端点之间存在着逻辑数据传输,而实际的数据传输是由USB总线接口层来完成的。 管道和USB设备中的端点一一对应。一个USB设备含有多少个端点,其和主机进行通信时就可以使用多少条管道,且端点的类型决定了管道中数据的传输类型,如中断端点对应中断管道,且该管道只能进行中断传输。 不论存在着多少条管道,在各个管道中进行的数据传输都是相互独立的。 |
|
|
|
USB物理层
6.1. USB接口 USB使用一根屏蔽的4线电缆与网络上的设备进行互联。数据传输通过一个差分双绞线进行,这两根线分别标为D+和D-,另外两根线是Vcc和Ground,其中Vcc向USB设备供电。使用USB电源的设备称为总线供电设备,而使用自己外部电源的设备叫做自供电设备。为了避免混淆,USB电缆中的线都用不同的颜色标记,如表所示。
6.2. 设备连接与设备速度检测 在USB设备连接时,USB系统能自动检测到这个连接,并识别出其采用的数据传输速率。 USB采用在D+或D-线上增加上拉电阻的方法来识别低速和全速设备。 USB支持三种类型的传输速率:1.5Mb/s的低速传输、12Mb/s的全速传输和480Mb/s的高速传输。 如图所示。
6.3.1. 差分传输 差分信号技术最大的特点是:必须使用两条线路才能表达一个比特位,用两条线路传输信号的压差作为判断1还是0的依据。这种做法的优点是具有极强的抗干扰性。倘若遭受外界强烈干扰,两条线路对应的电平同样会出现大幅度提升或降低的情况,但二者的电平改变方向和幅度几乎相同,电压差值就可始终保持相对稳定,因此数据的准确性并不会因干扰噪声而有所降低。 6.3.2. NRZ-I(No Return Zero-Inverse)非归零反相编码 如图描述了在USB电缆段上传输信息的步骤:
原Data信号被非归零反相编码后,NRZ-I电平只有正负电平之分,没有零电平,因此成为非归零编码。 非归零反相编码用NRZ-I电平的一次翻转来表示Data电平的逻辑0,与前一个NRZ-I电平相同的NRZ-I电平表示Data电平的逻辑1。既,遇到0转换,遇到1保持。 仔细观察,我们发现,NRZ-I编码信号经过反向后,还原的内容不变,可见数据信息由瞬时跳变沿所携带,其抗干扰性非常强。 由于没有采用同步时钟而是采用了信号本身的翻转来实现同步,若重复相同的1信号一直进入时,就会造成数据长时间无法转换,计时误差将逐渐积累,而导致接收器最终丢失同步信号,此时读取的时序会发生严重的错误。 因此,在NRZ-I编码之间,还需执行所谓的位填充的工作。位填充要求数据流中如果有连续的六个1就要强行转换。 如此一来,接收器在非归零反相编码数据流中最多每七个位就检测到一次跳转。这样就保证了接收器与输入数据流保持同步。要实现这个功能,非归零反相编码的发送器要能够把0(填充位)自动地插入到数据流中;而接收器也必须被设计成能够在连续的六个1之后识别一个自动跳转,并且立即扔掉这六个1之后的0位。 如图所示的第一行是送到接收器的原始数据。注意数据流包括连续的八个1。第二行表示对原始数据进行了位填充,在原始的第六个和第七个1之间填入了一个0。第七个1延时一个位时间让填充位插入。接收器知道连续六个1之后将是一个填充位,所以该位就要被忽略。注意,如果原始数据的第七个位是0,填充位也同样插入,在填充过的数据流中就会有两个连续的0。 |
||
|
||
只有小组成员才能发言,加入小组>>
934 浏览 1 评论
1090 浏览 1 评论
12506 浏览 0 评论
5922 浏览 3 评论
17716 浏览 6 评论
1022浏览 1评论
1013浏览 1评论
935浏览 1评论
4711浏览 1评论
1092浏览 1评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-21 17:47 , Processed in 0.887251 second(s), Total 57, Slave 49 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号