UPnP基本原理介绍

我们两清 提交于 2020-04-06 07:05:26

http://blog.csdn.net/braddoris/article/details/41576515

 

随着计算机产业以及计算机网络技术的迅猛发展,越来越多嵌入式设备的出现和家庭网络的发展,实现各种设备的互联互通已经成为人们的迫切需求,而实现家庭网络互联互通的关键是家庭网络的中间件技术。业界各大厂商都提出了自己的解决方案,其中以微软提出的UPnP最具有发展前途,也获得了最广泛的支持,目前UPnP基本是家庭网络设备必须支持的特性之一。

UPnP是通用即插即用(Universal Plug and Play)的缩写,主要用于设备的智能互联互通,使用UPnP协议不需要设备驱动程序,它可以运行在目前几乎所有的操作系统平台上,使得在办公室、家庭和其他公共场所方便地构建设备互联互通成为可能。

本文介绍了UPnP所定义的基本协议(如SSDP、GENA、SOAP等),重点分析了UPnP实现的基本工作流程,并通过抓包工具捕获数据包,对各种流程传递的协议报文进行详尽分析,最后结合NAT技术,重点叙述UPnP在NAT技术中的应用。

2      UPnP的结构规范

UPnP最大的愿景是希望任何设备一旦连接上网络,所有在网络上的设备马上就能知道有新设备加入,这些设备彼此之间能互相通信,更能直接使用或者控制它,一切都不需要人工设置,完全的即插即用。

2.1      UPnP的基本组件

服务、设备和控制点是UPnP网络的基本组件,它们之间的关系图如图1所示:

                                                                                                          图1  UPnP组件图

l  设备(Device)

UPnP网络中定义的设备具有很广泛的含义,各种各样的家电、电脑外设、智能设备、无线设备、个人电脑等等都可以称之为设备。一台UPnP设备可以是多个服务的载体或多个子设备的嵌套。

l  服务(Service)

在UPnP网络中,最小的控制单元就是服务。服务描述的是指设备在不同情况下的动作和设备的状态。例如,时钟服务可以表述为时间变化值、当前的时间值以及设置时间和读取时间两个活动,通过这些动作,就可以控制服务。

l  控制点(Control Point)

在UPnP网络中,控制点指的是可以发现并控制其他设备的控制设备。在UPnP网络中,设备可以和控制点合并,为同一台设备,同时具有设备的功能和控制点的功能,即可以作为设备提供服务,也可以作为控制点发现和控制其他设备。

2.2      UPnP的部分术语

l  UUID

UUID含义是通用唯一识别码(Universally Unique Identifier),其目的是让分布式系统中的所有元素都有唯一的标识,其格式为xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx(8-4-4-16),分别表示当前的日期、时间、始终序列、全局唯一的IEEE机器标识,如果有网卡,则从网络的MAC地址获取,没有网卡则以其他方式获得。

l  UDN

单一设备名字(Unique Device Name),基于UUID,表示一个设备,在不同的时间,对于同一台设备此值应该是唯一的。

l  URI

Web上可用的每种资源,包括HTML文档、图像、视频片段、程序等,由一个通用资源标志符(Universal Resource Identifier,简称”URI”)进行定位。URI一般有三部分组成:访问资源的命名机制、存在资源的主机名、资源自身的名称,由路径表示。考虑下面的URI,它表示了当前的HTML 4.0规范;http://www.webmonkey.com.cn/html/html40/它表示一个可通过HTTP协议访问的资源,位于主机www.webmonkey.com.cn上,通过路径“/html/html40”访问

l  URL

URL是URI命名机制的一个子集,URL是Uniform Resource Location的缩写,译为“统一资源定位符”。形象点说,URL是Internet上用来描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上,采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。

l  URN

URN是URL的一种更新形式,统一资源名称(Uniform Resource Name)。唯一标识一个实体的标识符,但是不能给出实体的位置。URN可以提供一种机制,用于查找和检索定义特定命名空间的架构文件。尽管普通的URL可以提供类似的功能,但是URN更强大更容易管理,因为它可以引用多个URL。

2.3      UPnP协议栈

UPnP定义了设备之间、设备和控制点、控制点之间通信的协议。完整的UPnP有设备寻址、设备发现、设备描述、设备控制、事件通知和基于Html的描述等几部分构成。UPnP设备协议栈如图2所示:

                                                                                                                   图2 UPnP协议栈

UPnP协议结构最底层的TCP/IP协议是UPnP协议结构的基础。IP层用于数据的发送与接收。对于需要可靠传送的信息,使用TCP进行传送,反之则使用UDP。UPnP对网络的底层没有要求,可以是以太网、WIFI、IEEE1394等等,只需支持IP协议即可。

构建在TCP/IP协议之上的是HTTP协议及其变种,这一部分是UPnP的核心,所有UPnP消息都被封装在HTTP协议及其变种中。HTTP协议的变种是HTTPU和HTTPMU,这些协议的格式沿袭了HTTP协议,只不过与HTTP不同的是他们通过UDP而非TCP来承载的,并且可用于组播进行通信。

2.3.1     SSDP协议

简单服务发现协议(Simple Service Discovery Protocol:SSDP),是内建在HTTPU/HTTPMU里,定义如何让网络上有的服务被发现的协议。具体包括控制点如何发现网络上有哪些服务,以及这些服务的资讯,还有控制点本身宣告他提供哪些服务。该协议运用在UPnP工作流程的设备发现部分。

2.3.2     SOAP协议

简单对象访问协议(Simple Object Access Protocol:SOAP)定义如何使用XML与HTTP来执行远程过程调用(Remote Procedure Call)。包括控制点如何发送命令消息给设备,设备收到命令消息后如何发送响应消息给控制点。该协议运用在UPnP工作流程的设备控制部分。

2.3.3     GENA协议

通用事件通知架构(Generic Event Notification Architecture:GENA)定义在控制点想要监听设备的某个服务状态变量的状况时,控制点如何传送订阅信息并如何接收这些信息,该协议运用在UPnP工作流程的事件订阅部分。

3      UPnP实现的工作流程

图3是UPnP的运行流程,我们先大概介绍下

                                                                                                               图3 UPnP的运行流程

1、 首先控制点和设备都先获取IP地址后才能进行下一步的工作;

2、 控制点首先要寻找整个网络上的UPnP设备,同时网络上的设备也要宣告自身的存在;

3、 控制点要取得设备的描述,包括这些设备提供什么样的服务;

4、 控制点发出动作信息给设备;

5、 控制点监听设备的状态,当状态改变时作出相应的处理动作;

3.1      寻址(Addressing)

UPnP网络的基础是TCP/IP,这就决定了每一个UPnP组件必须有IP地址。一台UPnP设备寻址的一般过程是:首先向DHCP服务器发送DHCP Discover的消息,如果在指定的时间内,设备没有收到DHCP Offer回应消息,设备必须使用AUTO-IP完成IP地址的获取。当然也可以使用静态配置的IP地址。

3.2      发现(Discovery)

连接到网络上的设备确定了IP地址之后,就会进入发现操作阶段。设备发现是UPnP实现的第一步。设备发现是由简单发现协议SSDP来完成的。当一台设备加入到网络中,发现过程允许设备向网络上的控制节点告知它提供的服务,当一个控制点加入到网络中,设备发现过程允许控制点寻找网络上感兴趣的设备。在这两种情况下,基本的交换信息就是发现消息。发现消息包括设备的一些特定信息或者某项服务的信息,例如它的类型、标志符、等等。图4是发现流程的框架图:

                                                                                                                 图4 发现过程框架图

3.3      描述(Description)

UPnP的第二步是设备描述。在控制点发现一台设备后,控制点对该设备可能仅仅知道设备或者服务的UPnP类型,设备的UUID和设备描述的URL地址,还需要知道更多的信息。控制点可以从发现消息中得到设备描述的URL,通过URL取回设备描述的信息。设备描述的一般过程图如图5所示:

                                                                                                           图5 设备描述以及服务描述

 

l  设备描述

UPnP对某一设备的描述以XML形式来表示,设备描述包括制造商信息、模块名称和编号、序列号等等。对于一个物理设备可以包含多个逻辑设备,多个逻辑设备既可以是一个根设备其中嵌入多个设备,也可以是多个根设备的方式存在。设备描述由设备制造商提供,采用XML描述,遵循UPnP框架协议。

l  服务描述

服务的描述包含一系列内容,具体有服务运行时刻的状态,运行时间等等。服务描述也由设备制造商提供,采用XML描述,遵循UPnP框架协议。

 

3.4      控制(Control)

在接收设备和服务描述之后,控制点可以向这些服务发出动作,同时控制点也可以轮询服务的当前状态。控制点将动作发送到设备服务,在动作完成或者失败后,服务返回相应的结果或者错误信息。其基本过程如图6所示:

         

                                                                                                               图6   控制过程示意图

为了控制一台设备,控制点向设备服务发出一动作,这一般是由控制点向服务的控制URL地址发送一个适当的控制消息。而服务则会对此动作出响应,返回相关的结果或错误。

3.5      事件(Even ting)

如上文的描述部分所述,一个即插即用服务描述包括服务响应的动作列表和运行时描述服务状态的变量列表。如果一个或多个状态被事件触发,服务将会在这些状态发生变化时发布更新,控制点可以订阅以获得此信息。在事件机制中,发布者指事件的来源(通常为设备服务),订阅者指事件目的地(通常为控制点)。

要订阅事件,订阅者可发送一条请求订阅消息。它将以这个订阅到持续时间作为响应。要保持订阅,订阅者必须在订阅过期之前进行续订。当订阅者不再需要发布者发送的事件时,订阅者应当取消其订阅。

发布者通过发送事件消息提醒订阅者状态改变。在订阅者第一次订阅时,需要发送一个专门的初始化事件消息。该事件消息包含所有事件的名称和值,并且允许订阅者初始化其服务状态。为了支持多个控制点,在动作生效后所有订阅者均会收到通知。由此,将向所有订阅者发送全部事件消息。事件消息使用HTTP协议传送,事件详细定义在通用事件通知结构(GENA)协议中。

3.6      展示(Presentation)

在控制点发现设备和取得设备描述之后,展示也就开始了。如果设备拥有进行展示的URL,那么控制点就可以通过此URL取得一个页面,在浏览器中加载该页面,并根据页面功能,支持用户控制设备或浏览设备状态。每一项完成的程度取决于展示页面和设备的具体功能。

设备展示包含在设备描述的Presentation URL字段。设备展示可以完全由设备制造商提供,它采用HTML页的形式,使用HTTP进行发布。图7是展示的流程示意图:

                                                                                                                     图7 展示示意图

4      UPnP在NAT中的应用

4.1      应用场景

如果用户是通过NAT接入Internet的,同时需要使用BC、电骡eMule等P2P这样的软件,这时UPnP功能就会带来很大的便利。利用UPnP能自动的把BC、电骡eMule等侦听的端口号映射到公网上,以便公网上的用户也能对NAT私网侧发起连接。

4.2      实现UPnP所需条件

必须同时满足三个条件:

l  NAT网关设备必须支持UPnP功能;

l  操作系统必须支持UPnP功能;我们常见的Windows XP是支持UPnP的;

l  应用软件必须支持UPnP功能;比如BC、电骡eMule、MSN软件都是支持的;

以上三个条件必须同时满足,缺一不可。

4.2.1        NAT网关设备的设置

NAT网关设备的UPnP功能,不同的型号设置界面略有不同,有的设备是默认使能UPnP功能的,有的设备是需要手工使能,不同的设备界面和方法可能略有不同,某款设备的设置具体如下:

                                                                                                        图8 网关设备上的UPnP使能

4.2.2        操作系统的UPnP功能设置

重点描述下Windows XP的UPnP功能如何启用。如果使用的是Windows XP SP2版本的系统,首先进入:控制面板——添加或删除程序——添加/删除Windows组件中,在“网络服务”中勾选“UPnP用户界面”,如图9:

                                                                                                                 图9 UPnP安装截图

确定后,系统会自动安装相应的组件,可能会提示你插入安装光盘,按照提示完成即可。接着打开Windows 自带的防火墙,在“例外”选项中勾选“UPnP框架”,如图10:

                                                                                                         图10 UPnP中防火墙的设置

接下来,在Windows中打开相应的UPnP服务:

进入“控制面板——管理工具——服务”,找到SSDP Discovery Service和Universal Plug and Play Device Host两项服务,选择启动即可。设置完以上后,就可以在“网络连接”中看到多了Internet网关,这表明添加UPnP已经成功了,如图10所示:

                          

                                                                                                       图11 UPnP成功后的网络接口

在应用层的设置就简单了,以BitComet v1.02版本为例来说明下。在选项——高级设置中,把“允许使用UPnP自动端口映射”前沟上。如图12所示:

                                                                                                          图12 BT软件中的端口映射

在“全局统计”页签中可以看到NAT端口映射已添加。这样在进行P2P下载时,在公网侧的其他用户也可以向处于私网中的用户发起连接,可以大大的提高下载效率与速度。如图13所示:

                                                                                                        图13 BT软件中侦听的端口号

点击“Internet连接”右键属性,再点设置,可以看到BitComet所侦听的TCP和UDP端口已经被映射出来了。如图14所示:

                                                                                                             图14 成功映射的端口号

接下来我们来抓包分析,NAT的端口映射如何通过UPnP来自动完成的?

4.3      发现阶段的报文交互

设备发现是UPnP网络实现的第一步,设备发现是由简单发现协议SSDP(Simple Service Discovery Protocol)来定义的。设备发现分两种情况:

4.3.1        主动告知

设备加入到网络中,设备发现过程允许设备向网络上的控制点告知它提供的服务,并且定期发送。

NOTIFY * HTTP/1.1

HOST:239.255.255.250:1900

CACHE-CONTROL: max-age = seconds until advertisement expires

LOCATION: URL for UPnP description for root device

NT: search target(服务类型)

NTS: ssdp:alive

USN: advertisement UUID(不同服务的统一服务名,标示相同类型服务能力)

 

通过Ethereal抓包可以发现,支持UPnP的网关设备启动后会发出一系列SSDP的alive消息,用于向外通告自己。图15是设备发出的一系列SSDP消息,图16是其中一条消息的详情。

                                                                                                             图15 SSDP消息截图一

                                                                                                             图16 SSDP消息截图二

 注意:上图location字段是网关向外通告了自己的IP地址以及UpnP监听的端口号,后续由设备向端口号2800发起TCP连接,利用XML来进行后续的描述、表示、控制等操作。

 

4.3.2     利用查询来发现

控制点加入到网络中时,设备发现过程允许控制点寻找网络上感兴趣的设备,并使得控制点获得设备能力的描述,同时控制点也可以向设备发送命令,侦听设备状态的改变,并将设备展示给用户。

查询消息

M-SEARCH * HTTP/1.1

HOST: 239.255.255.250:1900

MAN: ssdp:discover

MX:seconds to delay response

ST:search target

各个参数所表达的含义

MX:设置设备响应最长等待时间,设备响应在0和这个值之间随机选择响应延迟的值

ST:设置服务查询的目标,它必须是下面的类型:

     ssdp:all 搜索所有设备和服务

     upnp:rootdevice 仅搜索网络中的根设备

     uuid:device-UUID 查询UUID标识的设备

     urn:schemas-upnp-org:device:device-

     type:version查询device-Type字段指定的设备类型,设备类型和版本由UPNP组织定义

     urn:schemas-upnp-org:service:service-

     type:version 查询service-Type字段指定的服务类型,服务类型和版本由UPNP组织定义

图17是PC向外发送的查询报文

                                                                                                    图17 PC向外发送的查询报文截图

响应消息

HTTP/1.1 200 OK

CACHE-CONTROL: max-age = seconds until  advertisement expires

DATE: when reponse was generated

EXT:

LOCATION: URL for UPnP description for root device

SERVER: OS/Version UPNP/1.0 product/version

ST: search target

USN: advertisement UUID

各参数的意义

max-age指定通知消息存活时间,如果超过此时间间隔,控制点可以认为设备不存在

DATE: 指定响应生成的时间                                

EXT:向控制点确认MAN头域已经被设备理解

LOCATION:包含根设备描述得URL地址

SERVER:包含操作系统名,版本,产品名和产品版本信息。

ST:内容和意义与查询请求的相应字段相同

USN:表示不同服务的统一服务名,它提供了一种标识出相同类型服务的能力。

 

通过Ethereal抓包得到的响应消息,如图18所示:

                                                                                                                 图18 响应消息截图

当在网关设备上去使能UpnP功能时,设备会向外发送SSDP的byebye消息。

SSDP:byebye消息

NOTIFY * HTTP/1.1

HOST:239.255.255.250:1900

NT:search target

NTS: ssdp:byebye

USN: advertisement UUID

 

发出的SSDP的byebye利用Ethereal抓包解析,具体如图19所示:

                                                                                                     图19 SSDP的byebye 消息截图

4.4      描述阶段的报文交互

UPnP网络结构的第二步是设备描述。在控制点发现了一个设备之后,控制点仍然对设备知之甚少,控制点可能仅仅知道设备或服务的UPnP类型,设备的UUID和设备描述的URL地址。为了让控制点更多的了解设备和它的功能或者与设备交互,控制点必须从发现消息中得到设备描述的URL,通过URL取回设备描述。

设备描述是由设备制造商提供的,采用XML表述,并且遵循UPnP设备模版。此模版是由UPnP工作委员会生成的。设备描述包括制造商信息,包括模块名称和编号,序列号,制造商名称,制造商网站的URL等。对于一个物理设备可以包含多个逻辑设备,多个逻辑设备既可以是一个根设备其中嵌入多个设备,也可以是多个根设备的方式实现。

其中一个描述所建立的TCP连接如图20所示:

                                                                                                          图20 建立的TCP连接截图

用Ethereal的Follow TCP Stream来解析上面的报文:

GET /InternetGatewayDevice.xml HTTP/1.1

Accept: text/xml, application/xml

User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)

Host: 192.168.1.1:2800

Connection: Keep-Alive

Cache-Control: no-cache

Pragma: no-cache

 

HTTP/1.1 200 OK

Server:Unknown/0.0 UPnP/1.0 Conexant-EmWeb/R6_1_0

Connection: close Content-Type: text/xml

Expires: Thu, 01 Jan 1970 00:00:00 GMT

Cache-Control: no-cache Pragma: no-cache

 

<?xml version="1.0"?>

<root xmlns="urn:schemas-upnp-org:device-1-0">

  <specVersion>

    <major>1</major>

    <minor>0</minor>

  </specVersion>

  <URLBase>http://192.168.1.1:2800/</URLBase>

  <device>

    <deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>

    <friendlyName>Huawei-3Com IGD</friendlyName>

<manufacturer>Huawei-3Com</manufacturer>

<manufacturerURL>http://aolynk.huawei-3com.com/</manufacturerURL>

<modelDescription>Huawei-3Com UPnP IGD in ISOS 9.0.8.9</modelDescription>

<modelName>IGD</modelName>

<modelNumber>9.0.8.9</modelNumber>

<modelURL>http://www.vendor.com/model</modelURL>

<serialNumber>Prototype</serialNumber>

<UDN>uuid:ab270226-590c-8539-3c7d-8ee91a399470</UDN>

<UPC>Universal Product Code</UPC>

        <iconList>

      <icon>

 …………

4.5      控制阶段的报文交互

设备控制是UPnP网络的第三步。控制点先发送一个控制行为请求,要求设备开始服务,然后再按设备的URL发送相应的控制消息,控制消息是放置在XML文件中的那些SOAP格式的信息,最后,服务返回响应信息,指出服务是成功或是失败。对其中一个控制阶段所建立的TCP连接的如图21所示:

                                                                                                图21 控制阶段所建立的TCP连接截图

用Ethereal的Follow TCP Stream来解析上面的报文:

POST /EmWeb/UPnP/Control/4 HTTP/1.1

Content-Type: text/xml; charset="utf-8"

SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetSpecificPortMappingEntry"

User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)

Host: 192.168.1.1:2800

Content-Length: 625

Connection: Keep-Alive

Cache-Control: no-cache

Pragma: no-cache

<?xml version="1.0"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><m:GetSpecificPortMappingEntryxmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"><NewRemoteHostxmlns:dt="urn:schemas-microsoft-com:datatypes"dt:dt="string"></NewRemoteHost><NewExternalPortxmlns:dt="urn:schemas-microsoft-com:datatypes"dt:dt="ui2">25118</NewExternalPort><NewProtocolxmlns:dt="urn:schemas-microsoft-com:datatypes"dt:dt="string">TCP</NewProtocol></m:GetSpecificPortMappingEntry></SOAP-ENV:Body></SOAP-ENV:Envelope>

 

HTTP/1.1 200 OK

Server: Unknown/0.0 UPnP/1.0 Conexant-EmWeb/R6_1_0

Connection: close

Content-Type: text/xml; charset=utf-8

Expires: Thu, 01 Jan 1970 00:00:00 GMT

Cache-Control: no-cache

Pragma: no-cache

 

<s:Envelope

   xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"

   s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

  <s:Body>

<u:GetSpecificPortMappingEntryResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewInternalPort>25118</NewInternalPort><NewInternalClient>192.168.1.2</NewInternalClient><NewEnabled>1</NewEnabled><NewPortMappingDescription>BitComet (192.168.1.2:25118) 25118 TCP</NewPortMappingDescription><NewLeaseDuration>0</NewLeaseDuration></u:GetSpecificPortMappingEntryResponse>

  </s:Body>

</s:Envelope>

 

通过上面可以看出,PC利用通过UPnP向网关发送的SOAP格式的控制消息,请求BitComet的TCP的25118端口映射,网关返回OK消息。

4.6      事件阶段和展示阶段的报文交互

设备事件是UPnP网络的第四步。一个服务的UPnP描述包括服务响应的动作列表和运行时模拟服务状态的变量列表。当这些变量改变时,就会产生一个事件,系统将修改事件列表的内容,事件服务器将事件向整个网络广播。控制点也可以事先向事件服务器预约事件信息,保证控制点感兴趣的事件及时准确的传送过来。事件消息放在xml文件中,格式是GENA。在UpnP的自动端口映射没有该报文的交互。

NOTIFY delivery path HTTP/1.1

HOST: delivery host:delivery port

CONTENT-TYPE: text/xml

NT: upnp:event

NTS: upnp:propchange

SID: uuid:subscription-UUID

SEQ: event key

<e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0">

 <e:property>

 <variableName>new value</variableName>

 </e:property>

  Other variable names and values (if any) go here

</e:propertyset>

 

在展示阶段,UpnP的自动端口映射也没有该报文的交互。在此就略去。

 

upnp协议简介(一)

http://blog.csdn.net/braddoris/article/details/41646789

 

UPnP全名是Universal Plug and Play,主要是微软在推行的一个标准。简单的来说,UPnP 最大的愿景就是希望任何设备只要一接上网络,所有在网络上的设备马上就能知道有新设备加入,这些设备彼此之间能互相沟通,更能直接使用或控制它,一切都不需要设定,完全的Plug and Play。

-------------------------------------------------------------------------------------------------------

 

关于UPnP协议栈

UPnP设备体系结构包含了设备之间、控制点之间、设备和控制点之间的通信。完整的UPnP由设备寻址、设备发现、设备描述、设备控制、事件通知和基于Html的描述界面几部分构成。

1. UPnP是一个多层协议构成的框架体系,每一层都以相邻的下层为基础,同时又是相邻上层的基础。直至达到应用层为止。该图中的最下面是就是IP和TCP,共两层,负责设备的IP地址。

2. 三层是HTTP、HTTPU、HTTPMU,这一层,属于传送协议层。传送的是内容都经过“封装”后,存放在特定的XML文件中的。对应的SSDP、GENA、SOAP指的是保存在XML文件中的数据格式。到这一层,已经解决了UPnP设备的IP地址和传送信息问题。

3. 第四层是UPnP设备体系定义,仅仅是一个抽象的、公用的设备模型。任何UPnP设备都必须使用这一层。

4. 第五层是UPnP论坛的各个专业委员会的设备定义层,在这个论坛中,不同电器设备由不同的专业委员会定义,例如:电视委员会只负责定义网络电视设备部分,空调器委员会只负责定义网络空调设备部分……,依此类推。所有的不同类型的设备都被定义成一个专门的架构或者模板,供建立设备的时候使用。可以推知,进入这一层,设备已经被指定了明确用途。当然,这些都必须遵守标准化的规范。从目前看,UPnP已经可以支持大部分的设备:从电脑、电脑外设,移动设备和家用消费类电子设备等等,无所不包,随着这个体系的普及,将可能有更多的厂家承认这一标准,最终,可能演化为公认的行业标准。

5. 最上层,也就是应用层,由UPnP设备制造厂商定义的部分。这一层的信息是由设备制造厂商来“填充” 的,这部分一般有设备厂商提供的、对设备控制和操作的底层代码,然后,就是名称序列号呀,厂商信息之类的东西。

-------------------------------------------------------------------------------------------------------

 

关于UPnP的一些术语

● UUID

UUID含义是通用唯一识别码(Universally Unique Identifier),其目的是让分布式系统中的所有元素,都有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。其格式为xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx(8-4-4-16),分别为当前日期和时间,时钟序列,全局唯一的IEEE机器识别号,如果有网卡,从网卡mac地址获得,没有网卡以其他方式获得。

● UDN

单一设备名(Unique Device Name),基于UUID,表示一个设备。在不同的时间,对于同一个设备此值应该是唯一的。

● URI

 Web上可用的每种资源 - HTML文档、图像、视频片段、程序等 - 由一个通用资源标志符(Universal Resource Identifier,简称"URI")进行定位。 URI一般由三部分组成:访问资源的命名机制;存放资源的主机名;资源自身的名称,由路径表示。考虑下面的URI,它表示了当前的HTML 4.0规范:http://www.webmonkey.com.cn/html/html40/它表示一个可通过HTTP协议访问的资源,位于主机www.webmonkey.com.cn上,通过路径“/html/html40”访问。

● URL

URL是URI命名机制的一个子集,URL是Uniform Resource Location的缩写,译为“统一资源定位符”。通俗地说,URL是Internet上用来描述信息资源的字符串,主要用在各种www客户程序和服务器程序上。采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。

● URN

URN:URL的一种更新形式,统一资源名称(URN,Uniform Resource Name)。唯一标识一个实体的标识符,但是不能给出实体的位置。标识持久性Internet资源。URN可以提供一种机制,用于查找和检索定义特定命名空间的架构文件。尽管普通的URL可以提供类似的功能,但是在这方面,URN 更加强大并且更容易管理,因为 URN 可以引用多个 URL。

-------------------------------------------------------------------------------------------------------

 

关于UPnP组件

完整的UPnP服务系统由支持UPnP的网络和符合UPnP规范的设备共同构成的。

整个系统是由Device、Service、和Control Point三部分所构成。

设备(Device):

这里是指符合UPnP规范的设备。一个UPnP设备可以看成一个包含服务并嵌套了常规设备的“容器” 。例如,一个UPnP的VCR(录像机)设备可以包含磁带传送服务、调谐服务和时钟服务。就是说,UPnP之下的设备不能仅仅理解为硬件意义上的设备,而应当包括服务功能。

不同种类的UPnP设备将关联不同的设置、服务和嵌入设备。如打印机和VCR属于不同用途的设备,服务就不可能定义成一样的。

服务(Service):

设备执行用户请求的控制过程,可划分成一个个很小的阶段或单位,每个单位就称为一个服务。每一个服务,对外都表现为具体的行为和模式,而行为和模式又可以用状态和变量值进行描述。只要可以用数值描述,在计算机里面就容易处理了。例如,模仿一个时钟,它只有一个工作模式:这个模式就是模拟并显示当前的时间。而一个时钟的行为共有两种(也只有两种):

1. 设置时间(用来“即平时说的对表”).

2. 得到时间(用于显示时间)。

其它设备服务,也是用这样思路来描述和定义的,一个设备也可以被定义多个服务。不论是设备的定义信息和服务的描述信息,都保存在一个XML文件中,这个文件也是UPnP协议构成的一部分。当设备建立和使用服务的时候,XML文件可以与它们进行关联。

XML文件中还有一个很关键的“状态表”,状态表可进一步分为“服务状态表”和“事件状态表”。整个UPnP设备运行的全过程内,状态表贯穿始终,当设备状态改变的时候,例如发生参数变化或状态刷新的时候,立即就在“状态表”中反映出来。如控制服务器在接收到设置时间的行为请求时,就立即执行请求(对时操作),并给出响应,同时更新状态表中的有关数据。相应地,事件服务器负责向对此事件感兴趣的设备公布所发生的状态改变。例如,一个火灾事件发生后,事件服务器就向火灾报警器发布这个事件,导致报警器动作产生报警信号。

控制点(Control Point):

在UPnP网络中,用户请求设备执行的控制是通过控制点实现的,控制点首先是一个有能力控制别的设备的控制者,还要具有在网络中 “发现”控制目标的能力。在发现(控制目标)之后,控制点应当:

①取得设备的描述信息并得到所关联的服务列表。

②取得相关服务的描述。

③调用控制服务行为。

④确定服务的事件 “源”,不论何时,只要服务状态发生改变,事件服务器会立即向控制点发送一个事件信息。

从上面说到的各种信息,都保存在XML文件中,不同用途的信息,格式不同。保证可以各取所需,不会混淆。

-------------------------------------------------------------------------------------------------------

 

关于UPnP工作流程

 

1、寻址(Addressing):

地址是整个UPnP系统工作的基础条件,每个设备都应当是DHCP(Dynamic Host Configuration Protocol动态主机配置协议)的客户。当设备首次与网络建立连接后,利用DHCP服务,使设备得到一个IP地址。这个IP地址可以是DHCP系统指定的,也可以是由设备选择的,当然,有能力自己选择IP地址的设备,必然是那些“聪明”的设备才行!这也就是所谓的“自动”IP地址。

如果遇到本地DHCP管理范围之外的IP地址请求,还需要解决“友好设备”的地址分配问题,这个问题通常由域名服务器来解决。

2、发现(Discovery):

       可分成两种情况,一种是在有控制请求之后,在当前的网络中查找有无对应的可用设备;另一种情况是某一设备接入网络、取得IP地址之后,就开始向网络“广播”自己已经进入网络,即寻找控制请求。

       UPnP使用简单发现协议(SSDP)来完成发现,这是一个工作在UDP上的HTTP协议。

当一个设备加入网络,它将向组播发送类似如下的消息:

 

 

[html] view plaincopy
 
  1. NOTIFY * HTTP/1.1  
  2. Host:239.255.255.250:1900  
  3. Cache-control:max-age=1800  
  4. Location:http://192.168.0.1:49152/des.xml  
  5. Nt:upnp:rootdevice  
  6. Nts:ssdp:alive  
  7. Usn:uuid:de5d6118-bfcb-918e-0000-00001eccef34::upnp:rootdevice  

 

 

 

Host:这里必须使用IANA(InternetAssigned Numbers Authority)为SSDP预留的组播地址:239.255.255.250:1900。

Cache-control:max-age的数值表明设备将在这段时间(单位为秒)后失效,因此,设备应当在失效前,重发这样的消息,标准指出,这里的数值应当不小于1800秒,但实际上,这里的取值范围取决于UPnP的实现。

Location:设备描述文件的URL。

Nt:Notification Type,这里的值upnp:rootdevice)表明这是一个“根设备”。每个设备可以有自己的子设备。

Nts:Notification Sub Type,标准规定必须是ssdp:alive。

Usn:Unique Service Name,是一个设备实例的标识符。

         通过这样的消息,控制点便可以知道网络中的设备。

         与之对应的是,当控制点加入网络时,它也将组播一个消息,用来发现设备:

 

 

[html] view plaincopy
 
  1. M-SEARCH* HTTP/1.1  
  2. Host:239.255.255.250:1900  
  3. Man:"ssdp:discover"  
  4. Mx:5  
  5. ST:ssdp:rootdevice  

 

 

 

Host:同上。

Man:必须是“ssdp:discover”。

Mx:1到5之间的一个值,表示最大的等待应答的秒数。

ST:Seatch Targer,表示搜索的节点类型。

 

设备可以根据这样的搜索产生应答:

 

 

[html] view plaincopy
 
  1. HTTP/1.1200 OK  
  2. Cache-control:max-age=1800  
  3. Ext:  
  4. Location:http://192.168.0.1:2345/xx.xml  
  5. Server:Microsoft-Windows-NT/5.1UPnP/1.0 UPnP-Device-Host/1.0  
  6. ST:ST:urn:schemas-upnp-org:service:ContentDirectory:1  
  7. USN:uuid:60b2e186-b084-44af-ac09-1c64ea1bb364::urn:schemas-upnp-org:service:ContentDirectory:1  

 

 

 

3、描述(Description):

简单说,这是声明“自己”是什么样的设备,例如名称、制造厂商、序列号码等等。刚开始“发现”设备后,控制点对这个设备的“了解”还很少,需要依据ULR找到该设备的描述文件,从这些文件中读取更多的描述信息。描述信息的范围很广,一般都是由设备的制造厂商提供的。主要的描述项目有:控制的模式名称和模式号码、设备序列号、制造厂商名称、厂商的WEB的ULR等等。这些一般都存放在特定的XML文件中。

设备的描述通过HTTP协议来完成。

 

[html] view plaincopy
 
  1. <?xmlversionxmlversion="1.0" encoding="utf-8"?>  
  2. <rootxmlnsrootxmlns="urn:schemas-upnp-org:device-1-0">  
  3.   <specVersion>  
  4.     <major>1</major>  
  5.     <minor>1</minor>  
  6.   </specVersion>  
  7.    
  8.   <device>  
  9.    <deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType>  
  10.     <friendlyName>KitchenLights</friendlyName>  
  11.    <manufacturer>OpenedHand</manufacturer>  
  12.     <modelName>VirtualLight</modelName>  
  13.    <UDN>uuid:cc93d8e6-6b8b-4f60-87ca-228c36b5b0e8</UDN>  
  14.    
  15.     <serviceList>  
  16.       <service>  
  17.        <serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType>  
  18.        <serviceId>urn:upnp-org:serviceId:SwitchPower:1</serviceId>  
  19.        <SCPDURL>/SwitchPower1.xml</SCPDURL>  
  20.         <controlURL>/SwitchPower/Control</controlURL>  
  21.        <eventSubURL>/SwitchPower/Event</eventSubURL>  
  22.       </service>  
  23.     </serviceList>  
  24.   </device>  
  25. </root>  

 

 

 

deviceType:设备类型,格式为:“urn:schemas-upnp-org:device:deviceType:v”,这里deviceType和v是由设备定义的。

friendlyName:一个更加友好的设备名。

Manufacturer:制造商。

modeName:型号。

UDN:Unique Device Name,设备的UUID。

serviceList:服务列表。

对于每一个服务:

serviceType:与deviceType类似,这里的后两段由服务定义。

serviceId:服务ID,通常于serviceType对应。

SCPDURL:服务描述的URL。

controlURL:用于控制的URL。

eventSubURL:用于订阅事件的URL。

 

一个服务描述的示例如下:

 

[html] view plaincopy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <scpd xmlns="urn:schemas-upnp-org:service-1-0">  
  3.   <specVersion>  
  4.    <major>1</major>  
  5.    <minor>1</minor>  
  6.   </specVersion>  
  7.   <actionList>  
  8.     <action>  
  9.      <name>SetTarget</name>  
  10.       <argumentList>  
  11.         <argument>  
  12.           <name>NewTargetValue</name>  
  13.          <relatedStateVariable>Target</relatedStateVariable>  
  14.          <direction>in</direction>  
  15.         </argument>  
  16.       </argumentList>  
  17.     </action>  
  18.     <action>  
  19.      <name>GetTarget</name>  
  20.       <argumentList>  
  21.         <argument>  
  22.          <name>RetTargetValue</name>  
  23.          <relatedStateVariable>Target</relatedStateVariable>  
  24.          <direction>out</direction>  
  25.         </argument>  
  26.       </argumentList>  
  27.     </action>  
  28.     <action>  
  29.      <name>GetStatus</name>  
  30.       <argumentList>  
  31.         <argument>  
  32.          <name>ResultStatus</name>  
  33.          <relatedStateVariable>Status</relatedStateVariable>  
  34.          <direction>out</direction>  
  35.         </argument>  
  36.       </argumentList>  
  37.     </action>  
  38.   </actionList>  
  39.   <serviceStateTable>  
  40.     <stateVariablesendEventsstateVariablesendEvents="no">  
  41.      <name>Target</name>  
  42.      <dataType>boolean</dataType>  
  43.      <defaultValue>0</defaultValue>  
  44.     </stateVariable>  
  45.     <stateVariablesendEventsstateVariablesendEvents="yes">  
  46.      <name>Status</name>  
  47.      <dataType>boolean</dataType>  
  48.       <defaultValue>0</defaultValue>  
  49.     </stateVariable>  
  50.   </serviceStateTable>  
  51. </scpd>  

 

 

 

actionList定义了“行为”,serviceStateTable定义了“状态变数”。

每一个行为都由一个名称(name)和若干参数(argument)组成。二参数由名字(name)、传递方向(direction,取值in或者out)以及关联的状态变数(relatedStateVariable)组成。

状态变数之所以叫做状态变数,是用来标明UPnP设备或程序的一些状态的。一个程序可以订阅(subscribe)状态的变化,从而得到通知。而一个参数之所以必须关联一个状态变数,是因为状态变数的类型决定了参数的类型。

4、控制(Control):

控制点找到设备描述之后,会从描述中“提炼”出要进行的操作并获悉所有的服务;对每个UPnP设备来说,这些描述必须是很确切、很详细的,描述中可能包含有命令或行为列表、服务响应信息、用到的参数等等。对于服务的每个行为,也伴有描述信息:主要是整个服务进行期间的变量、变量的数据类型、可用的取值范围和事件的特征。

要控制某个设备,控制点必须先发送一个控制行为请求,要求设备开始服务,然后再按设备的ULR发送相应的控制消息,控制消息就是放置在XML文件中的那些SOAP格式的信息。最后,服务会返回响应信息,指出服务是成功或是失败。

UPnP使用SOAP完成控制。SOAP工作在HTTP上,使用XML来描述远程调用并返回结果。

 

[html] view plaincopy
 
  1. POST /control/url HTTP/1.1  
  2. HOST: hostname:portNumber  
  3. CONTENT-TYPE: text/xml;charset="utf-8"  
  4. CONTENT-LENGTH: length ofbody  
  5. USER-AGENT: OS/versionUPnP/1.1 product/version  
  6. SOAPACTION:"urn:schemas-upnp-org:service:serviceType:v#actionName"  
  7.    
  8. <?xml version="1.0"?>  
  9. <s:Envelope  
  10.  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"  
  11.  s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">  
  12.     <s:Body>  
  13.         <u:actionNamexmlns:uu:actionNamexmlns:u="urn:schemas-upnp-org:service:serviceType:v">  
  14.            <argumentName>in arg value</argumentName>  
  15.         </u:actionName>  
  16.     </s:Body>  
  17. </s:Envelope>  

 

 

actionName和argumentName就是在协议描述中定义的行为名称和参数名称。

而调用的结果同样以XML方式返回:

 

[html] view plaincopy
 
  1. HTTP/1.1 200 OK  
  2. CONTENT-TYPE: text/xml;charset="utf-8"  
  3. DATE: when response wasgenerated  
  4. SERVER: OS/version UPnP/1.1product/version  
  5. CONTENT-LENGTH: bytes inbody  
  6.    
  7. <?xmlversionxmlversion="1.0"?>  
  8. <s:Envelope  
  9.  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"  
  10.  s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">  
  11.     <s:Body>  
  12.         <u:actionNameResponsexmlns:uu:actionNameResponsexmlns:u="urn:schemas-upnp-org:service:serviceType:v">  
  13.             <argumentName>out arg value</argumentName>  
  14.         </u:actionNameResponse>  
  15.     </s:Body>  
  16. </s:Envelope>  

 

 

 

5、事件(Eveting):

在服务进行的整个时间内,只要变量值发生了变化或者模式的状态发生了改变,就产生了一个事件,系统将修改上述提到的事件列表的内容。随之,事件服务器把事件向整个网络进行广播。另一方面,控制点也可以事先向事件服务器预约事件信息,保证将该控制点感兴趣的事件及时准确地传送过来。

广播或预约事件,传送的都是事件消息,事件消息也放在XML文件中,使用的格式是GENA。设备投入工作之前的准备―――初始化过程,也是一个事件,初始化需要的各种信息也是用事件消息传送的。包括的内容主要是:变量初始值,模式的初始状态等等。

订阅的URL事在服务描述中给出的。

 

[html] view plaincopy
 
  1. SUBSCRIBE publisher pathHTTP/1.1  
  2. HOST: publisherhost:publisher port  
  3. USER-AGENT: OS/versionUPnP/1.1 product/version  
  4. CALLBACK: <deliveryURL>  
  5. NT: upnp:event  

 

 

 

此处,NT取upnp:event表示订阅事件;CALLBACK的值是回调的URL。

       与之对应的事订阅的应答:

 

[html] view plaincopy
 
  1. HTTP/1.1 200 OK  
  2. DATE: when response was generated  
  3. SERVER: OS/version UPnP/1.1 product/version  
  4. SID: uuid:subscription-UUID  
  5. CONTENT-LENGTH: 0  
  6. TIMEOUT: Second-1800  

 

 

 

SID:本订阅的标识符,通常使用UUID。

TIMETOUT:这里的值表示本订阅的有效期。这意味着在超时前,必须续订。

 

续订的请求与订阅类似,只是附加了SID:

 

[html] view plaincopy
 
  1. SUBSCRIBE publisher path HTTP/1.1  
  2. HOST: publisher host:publisher port  
  3. SID: uuid:subscription UUID  
  4.    

 

 

退订也类似:

 

[html] view plaincopy
 
  1. UNSUBSCRIBE publisher path HTTP/1.1  
  2. HOST: publisher host:publisher port  
  3. SID: uuid:subscription UUID  

 

 

 

事件消息:

 

[html] view plaincopy
 
  1. NOTIFY delivery path HTTP/1.1  
  2. HOST: delivery host:delivery port  
  3. CONTENT-TYPE: text/xml; charset="utf-8"  
  4. NT: upnp:event  
  5. NTS: upnp:propchange  
  6. SID: uuid:subscription-UUID  
  7. SEQ: event key  
  8. CONTENT-LENGTH: bytes in body  
  9.    
  10. <?xml version="1.0"?>  
  11. <e:propertysetxmlns:ee:propertysetxmlns:e="urn:schemas-upnp-org:event-1-0">  
  12.     <e:property>  
  13.        <variableName>new value</variableName>  
  14.     </e:property>  
  15. </e:propertyset>  

 

 

 

这里,每个产生事件的状态变数对应一个e:property标识,variableName是变数名。

此外,SEQ是消息的顺序号,从0开始。

当订阅者收到消息之后,必须在30秒内发送确认。

HTTP/1.1 200 OK

 

如果订阅者没有确认,设备仍然会发送之后的消息,直到本次订阅超时。

6、展示(Presentation):

只要得到了设备的ULR,就可以取得该设备表达页面的ULR,然后可以将此表达纳入用户的本地浏览器上。这部分还包括与用户对话的界面,以及与用户进行会话的处理。

-------------------------------------------------------------------------------------------------------

 

关于UPnP linux的体系结构

 

1、  设备/控制点

调用UPnP的标准API来实现设备和控制点的功能。

2、  UPnP SDK

UPnP软件开发包API部分将UPnP协议核的详细内容从控制点和服务器申请中抽象出来,并且给了一个统一界面的入口函数,里面包含了SSDP,GENA和SOAP等。

3、  WEB server

微型服务器模块处理一个标准的HTTP GET请求。在UPnP组成元素中,都要求使用基本的HTTP服务,所以需要使用微型服务器模块来完成基本的HTTP服务。微型服务器模块管理文档的定位,这些文档一般对GET命令有效,并且运行使用HTTP协议的数据流进行传输。

微型服务器也支持虚拟路径HTTP POST请求,但不支持其他种类的请求。

4、  XML解析器

XML在UPnP中被广泛地使用。描述文档就是XML文档。GENA使用XML来描述一个服务状态的描述变化。SOAP使用XML来格式化请求和响应。软件开发包SDK包含一个XML解析,这个XML解析会被UPnP协议和客户端或服务端软件使用。

5、  线程库

UPnP协议栈的实现中大量采用了多线程技术,该模块就是为了更方便高校地使用线程技术,其中包含了一个定时器线程子模块和一个线程池子模块。线程池子模块用于管理协议栈中所有的线程;定时器线程子模块用来处理协议栈中所有的定时事件。

应用层在调用API UpnpInit()时会初始化两个缓冲池:发送缓冲池和接收缓冲池。在创建每个缓冲池时都要给定一个缓冲池的属性作为参数,以确定在该缓冲池中最少,最多可以容纳的线程数,然后调用CreateWorker()创建所需的线程。

当有新的任务要执行的时候,调用TPJobInit(),ThreadPoolAddPersistent()或者T火热阿迪PoolAdd()将任务加到缓冲池的相应队列中,等待空闲的线程调用执行。

6、  HTTP解析器

设备公告消息、设备查询消息、设备查询响应消息都是用HTTP协议来封装的,使用SSDP协议定义的头和方法,这需要开发者自己来解释这些消息。同样,事件订阅消息和事件取消订阅消息也是用HTTP协议来封装的,使用了GENA定义的头和方法,也需要开发者自己解析这些消息,这里把这两部分的HTTP消息解析合并为一个模块:HTTP消息的解析。通常的HTTP消息是由浏览器或者www服务器来解析的,这里的HTTP消息解析只对SSDP、GENA定义的特殊的HTTP消息进行解析。

7、  微型服务器

提供GENA、SOAP、SSDP、mini WEB server需要的公共功能,这一层接收所有的网络连接,并决定哪个请求可以进入上层,将HTTP头部交给HTTP模块去解析 ,并将这个连接转向合适的协议去处理。

 http://blog.csdn.net/braddoris/article/details/41646809

关于DLNA框架

 

1、Networking & Connectivity

为了解决物理设备连通问题,

主要依赖于Ethernet,802.11,Ipv4协议栈,Ipv6协议栈。

TCP/IP协议栈必须包含Ipv4,TCP,UDP,DHCP,Auto-IP,ARP,ICMP。

2、Device Discovery&Control

为了解决设备发现和互操作问题,实现所谓的“设备零配置”。比如通过电视播放PC媒体的时候,电视设备需要“自动知道”PC媒体服务器的存在,以及其能提供何种服务。

主要依赖于UPnP设备体系结构标准,XML,SOAP,HTTP等。

3、Media Management

为了解决媒体的标志,管理和分发。

主要依赖于UPnP AV v1.0的规格

ContentDirectory(DMS):

         浏览/查找所有的媒体文件

        包含了metadata,例如标题,创建者,分辨率等。

管理内容,比如创建播放列表,添加新的项目。

RenderingControl(DMP):

控制rendering的特性,比如音量,背光等。

ConnectionManager(DMP,DMS):

列举支持的传输协议和数据格式

列举已经存在的UPnP AV流

AV Transport(DMP,DMS):

         控制活动和位置,比如播放,暂停,快进,快退等。

4、Media Transport

解决服务端如何“流化”媒体内容到媒体展示端。

依赖于HTTP1.1,通过关闭TCP连接关闭媒体流。

 

5、Media Formats

解决媒体内容如何编码和标志。

定义了media format profiles以及媒体交互规则。

 

miniserver具体的流程如下:


 

 

DMR回调处理函数


 

 

DMS回调处理函数


 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!