DLNA第一步UPnP协议栈
前面公司有DLNA项目,研究了一下,在网上关于DLNA的资源很少,就将自己的心得写出来,以供参考。
其它的关于DLNA的介绍就不多说,要了解DLNA需要了解upnp,因为DLNA在upnp之上,初学者可以从http://www.upnp.org下载upnp的资料.也欢迎大家加入197683240 DLNA交流群。
upnp分为四步:发现 、描述 、控制 、事件
发现
当一个UPnP的设备加入网络,并想知道什么UPnP服务在网络上可用,它发送一个发现消息多播地址239.255.255.250端口1900通过UDP协议。此消息包含一个头,类似于一个HTTP请求。该协议有时被称为为HTTPU(HTTP通过UDP):
M-SEARCH * HTTP/1.1
ST: upnp:rootdevice
MX: 3
MAN: "ssdp:discover"
所有其他UPnP设备或方案都必须回应此消息类似的消息发送回设备,使用UDP单播,宣布该设备或程序实现的UPnP型材。一个有趣的怪癖:发送UDP单播设备发现消息被送往港口。对于每一个配置文件,它实现发送一条消息:
HTTP/1.1 200 OK
ST:upnp:rootdevice
USN:uuid:1d8ec8a7-4736-4598-9950-9710c992e471::upnp:rootdevice
Location:http://172.16.11.205:2869/upnphost/udhisapi.dll?content=uuid:1d8ec8a7-4736-4598-9950-9710c992e471
OPT:"http://schemas.upnp.org/upnp/1/0/";ns=0101-NLS:a06cdf4dcc4f213129a39f9b2ae98977
Cache-Control:max-age=3200
Server:Microsoft-Windows-NT/5.1 UPnP/1.0UPnP-Device-Host/1.0
在定期间隔的UPnP功能的设备或程序发送一条消息,宣布他们的服务。一个通知消息是或多或少相同,但发现响应消息发送到239.255.255.250组播地址通过UDP
1900端口上的UPnP有ST头,取而代之的是一个类似头NT头。
描述
每个配置文件提供了本身的描述和它提供的服务,并通过XML提供。从发现阶段的响应消息中包含一个头称为位置(不区分大小写),这是一个XML格式的文件可以下载的网址。这个文件描述(或相当:应说明)配置文件,设备或计划实施,控制和事件相应命令发送到专门的网址,但也可能是其他有关设备的元信息,如图标,这应该是显示Windows资源管理器,设备制造商,依此类推。
有没有这个头文件的默认值。事实上,在一些设备,尤其是对一个Broadcom芯片为基础的,它被设置在启动时动态。唯一的方法是完全肯定的是永远做设备发现。
控制
在该协议的第三步是“控制”:设备或程序可以要求其他设备或程序执行客户的名义采取行动,使用SOAP。 SOAP是一个协议,运行在HTTP上使用XML来描述远程过程调用服务器和从这些调用的返回结果。 SOAP主要用于基于网络的服务。对于每一个主要的编程语言库,可以用来实现SOAP请求和处理SOAP响应。
请求服务是通过发送一个SOAP请求到正确的参数,所谓的“控制URL”的控制点。为控制特定的配置文件的URL地址,可以发现在XML文件的URL在Location头从描述阶段发现内的<service>标签。配置文件标记看起来像这样:
<service>
<serviceType>urn:dmc-samsung-com:service:SyncManager:1</serviceType>
<serviceId>urn:dmc-samsung-com:serviceId:SyncManager</serviceId>
<controlURL>/upnphost/udhisapi.dll?control=uuid:1d8ec8a7-4736-4598-9950-9710c992e471+urn:dmc-samsung-com:serviceId:SyncManager</controlURL>
<eventSubURL>/upnphost/udhisapi.dll?event=uuid:1d8ec8a7-4736-4598-9950-9710c992e471+urn:dmc-samsung-com:serviceId:SyncManager</eventSubURL>
<SCPDURL>/upnphost/udhisapi.dll?content=uuid:bdccc2ab-dcdf-4c18-beee-226cc7df1f94</SCPDURL>
</service>
只发送SOAP请求URL内controlURL标签是必要的。这取决于哪些行动可以执行的配置文件。在在SCPDURL标记的URL的URL是所谓的“服务描述的URL”。它描述了SOAP方法可以进行该配置什么所谓的状态变量配置文件。在这个文件是什么,应符合设备提供服务,但在实践中,他们似乎总是不相匹配。
事件
UPnP中有这样的概念,被称为“状态变量”。这些变量,因为这个名字说,用于保持某种形式的状态中的UPnP设备和方案。一个程序可以订阅状态的变化:当状态变量改变时,新的状态被发送到所有程序/设备已订阅的事件。程序/设备可以订阅一个服务的状态变量,并签署一个网址,可以发现所指出的位置的URL。
<service>
<serviceType>urn:dmc-samsung-com:service:SyncManager:1</serviceType>
<serviceId>urn:dmc-samsung-com:serviceId:SyncManager</serviceId>
<controlURL>/upnphost/udhisapi.dll?control=uuid:1d8ec8a7-4736-4598-9950-9710c992e471+urn:dmc-samsung-com:serviceId:SyncManager</controlURL>
<eventSubURL>/upnphost/udhisapi.dll?event=uuid:1d8ec8a7-4736-4598-9950-9710c992e471+urn:dmc-samsung-com:serviceId:SyncManager</eventSubURL>
<SCPDURL>/upnphost/udhisapi.dll?content=uuid:bdccc2ab-dcdf-4c18-beee-226cc7df1f94</SCPDURL>
</service>
描述文件如:
<?xml version="1.0" ?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:dmc-samsung-com:device:SyncServer:1</deviceType>
<friendlyName>QPC-20120228LBE</friendlyName>
<manufacturer>Samsung-Electronics</manufacturer>
<manufacturerURL>http://www.samsung.com</manufacturerURL>
<modelDescription>QPC-20120228LBE-Laptop</modelDescription>
<modelName>Kies Sync Server</modelName>
<modelNumber>1.0</modelNumber>
<modelURL>http://www.samsung.com</modelURL>
<UDN>uuid:1d8ec8a7-4736-4598-9950-9710c992e471</UDN>
<serviceList>
<service>
<serviceType>urn:dmc-samsung-com:service:SyncManager:1</serviceType>
<serviceId>urn:dmc-samsung-com:serviceId:SyncManager</serviceId>
<controlURL>/upnphost/udhisapi.dll?control=uuid:1d8ec8a7-4736-4598-9950-9710c992e471+urn:dmc-samsung-com:serviceId:SyncManager</controlURL>
<eventSubURL>/upnphost/udhisapi.dll?event=uuid:1d8ec8a7-4736-4598-9950-9710c992e471+urn:dmc-samsung-com:serviceId:SyncManager</eventSubURL>
<SCPDURL>/upnphost/udhisapi.dll?content=uuid:bdccc2ab-dcdf-4c18-beee-226cc7df1f94</SCPDURL>
</service>
</serviceList>
</device>
</root>
1.搜索目前网络上的UPnP设备。Control Point生成一个MulticastSocket,绑定多播地址239.255.255.250 1900端口,然后发送一个搜索请求,默认将TimeToLive设为4,该请求在UPnP Device Architecture中是如下定义的:
M-SEARCH *HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: seconds to delay response
ST: search target
要注意的一点,该请求基于 HTTPMU(HTTP Multicast over UDP),上面这些信息都是属于HTTP Header,没有HTTP Body,而HTTP Header和HTTP Body之间是有一个空白行分隔的,通过Socket发送出去的时候不要忘了发送那个空白行,以后提到的消息也都请注意这一点。
UPnP设备收到该请求后会延时相当于Random.nextInt(MX)返回响应,以便Control Point能够有充足时间来处理请求;ST是要搜索的目标,如果搜索所有的设备和服务,则为ssdp:all,如果是搜索根设备,则为 upnp:rootdevice,象大部分程序中使用UPnP是为了找到支持UPnP的网关来动态映射端口,则可以赋为urn:schemas-upnp-org:device:InternetGatewayDevice:1。
下面是一个示例,搜索所有的根设备,这些设备收到该消息后应该在0~3秒内返回响应:
M-SEARCH* HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 3
ST: upnp:rootdevice
2.网络上的UPnP设备返回响应。如果该UPnP设备和要搜索的UPnP设备匹配,则该设备会返回一个响应,响应的格式在UPnP Device Architecture中是如下定义的:
HTTP/1.1200 OK
CACHE-CONTROL: max-age = seconds untiladvertisement expires
DATE: when response 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表示收到该消息后若干秒内没有收到该设备发出的任何通知消息,就认为该设备已经不存在网络上了;LOCATION表示该设备的描述文件,用于确定该设备包含哪些逻辑设备和哪些服务等等;USN表示Unique Service Name。
比如对于上面那条示例搜索消息,我的ADSL返回的响应是:
HTTP/1.1 200 OK
CACHE-CONTROL:max-age=1800
EXT:
LOCATION:http://10.0.0.138:80/IGD.xml
SERVER:SpeedTouch 510 4.0.2.0.1 UPnP/1.0 (14E31Y7)
ST:upnp:rootdevice
USN:uuid:UPnP-SpeedTouch510-1_00-90-D0-7F-AD-37::upnp:rootdevice
3.接下来就是取得该设备的描述文件,用于确定该设备信息和所支持的 功能。通过上面的响应信息的LOCATION属性,可以得到一个URL,可以通过HTTP请求该URL得到该设备的描述文件。注意,仅仅在搜索和通知的时 候是基于UDP的,其余的都是基于TCP的。设备描述文件定义可在UPnP Device Architecture中找到,比较长就不贴了。
比如上面我的ADSL返回LOCATION是http://172.16.11.205:80/IGD.xml,访问该地址,返回的一个XML片断是:
<?xmlversion="1.0" ?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://172.16.11.205</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<friendlyName>SpeedTouch 510 (14E31Y7)</friendlyName>
<manufacturer>THOMSON multimedia</manufacturer>
<manufacturerURL>http://www.thomson-multimedia.com</manufacturerURL>
<modelDescription>DSL Internet Gateway</modelDescription>
<modelName>SpeedTouch</modelName>
<modelNumber>510</modelNumber>
<modelURL>http://www.speedtouch.com</modelURL>
<serialNumber>14E31Y7</serialNumber>
<UDN>uuid:UPnP-SpeedTouch510-1_00-90-D0-7F-AD-37</UDN>
<presentationURL>/index.htm</presentationURL>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
<serviceId>urn:upnp-org:serviceId:layer3f</serviceId>
<controlURL>/upnp/control/layer3f</controlURL>
<eventSubURL>/upnp/event/layer3f</eventSubURL>
<SCPDURL>/Layer3Forwarding.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
......
</deviceList>
</device>
</root>
在UPnP规范中规定,一个设备可以包含若干的嵌入设备和服务。比如对于最常用到的InternetGateway Device中,UPnP InternetGatewayDevice模板中规定
可以看到在根设备中包含了Layer3 Forwarding Service和两个嵌入设备:WANDevice和LANDevice,而WANDevice下面又包含了若干WANConnectionDevice等等。
4.得到设备所提供的服务描述。在刚才的设备描述中有一个ServiceList节点,该节点下每个Service节点都包含一个SCPDURL节点,这个就是服务描述文件所在的位置,比如上面我的ADSL中Layer3 Forwarding Service服务描述文件的位置就是/Layer3Forwarding.xml,再组合URLBase节点属性值http://172.16.11.205,即得到该服务描述文件URL为http://172.16.11.205/Layer3Forwarding.xml,该文件详细的描述了该服务所提供的操作列表以及相应的参数和参数范围。
5.调用服务所提供的操作。调用是通过发送相应SOAP消息到该服务的控制URL上来完成的。该信息在UPnP Device Architecture中是如下定义的:
POST path of control URL HTTP/1.1
HOST: host of control URL:portof control URL
CONTENT-LENGTH: bytes in body
CONTENT-TYPE: text/xml; charset="utf-8"
SOAPACTION: "urn:schemas-upnp-org:service:serviceType:v#actionName"
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
<argumentName>in arg value</argumentName>
otherin args and their values go here, if any
</u:actionName>
</s:Body>
</s:Envelope>
就用在IGD设备上增加端口映射这个操作来举例,将网关的5678端口映射到内网10.0.0.1的8765端口,该操作被发送的SOAP消息如下:
POST/upnp/control/wanpppcpppoe HTTP/1.0
CONTENT-TYPE: text/xml; charset="utf-8"
HOST: 172.16.11.205:80
CONTENT-LENGTH: 649
SOAPACTION: "urn:schemas-upnp-org:service:WANPPPConnection:1#AddPortMapping"
<?xmlversion="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:AddPortMappingxmlns:u="urn:schemas-upnp-org:service:WANPPPConnection:1">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>5678</NewExternalPort>
<NewProtocol>tcp</NewProtocol>
<NewInternalPort>8765</NewInternalPort>
<NewInternalClient>10.0.0.1</NewInternalClient>
<NewEnabled></NewEnabled>
<NewPortMappingDescription></NewPortMappingDescription>
<NewLeaseDuration></NewLeaseDuration>
</u:AddPortMapping>
</s:Body>
</s:Envelope>
操作成功,设备的返回值是:
HTTP/1.0200
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: SpeedTouch 510 4.0.2.0.1 UPnP/1.0 (14E31Y7)
CONTENT-LENGTH: 304
Connection: close
EXT:
<?xmlversion="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<m:AddPortMappingResponsexmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1"></m:AddPortMappingResponse>
</s:Body>
</s:Envelope>
6.在设备一些属性变化了的时候,如果ControlPoint订阅了它的事件通知,则它会发送相应的通知给Control Point。在androiddlnaplayer中有个SSDPNotifySocketList来完成此事。ControlPoint注册后通过deviceNotifyReceived回调来通知ControlPoint。
SSDP协议消息
3.1 设备通知消息
在设备加入网络,UPnP发现协议允许设备向控制点广告它的服务。它使用向一个标准地址和端口多址传送发现消息来实现。控制点在此端口上侦听是否有新服务加入系统。为了通知所有设备,一个设备为每个其上的嵌入设备和服务发送一系列相应的发现消息。每个消息也包含它表征设备或服务的特定信息。
3.1.1 ssdp:alive消息
在设备加入系统时,它采用多播传送方式发送发现消息,包括告知设备包含的根设备信息,所有嵌入设备以及它包含的服务。每个发现消息包含四个主要对象:
- 在NT头中包含的潜在搜索目标。
- 在USN头中包含的复合发现标识
- 在LOCATION头中关于设备信息的URL地址
- 在CACHE-CONTROL头中表示的广告消息的合法存在时间。
对于根设备,存在三种发现消息:
NT |
USN |
根设备的UUID |
根设备的UUID |
设备类型:设备版本 |
根设备的UUID,设备类型:设备版本 |
upnp:rootdevice |
根设备的UUID,设备类型和upnp:rootdevice |
对于根设备,存在两种发现消息:
NT |
USN |
嵌入设备的UUID |
嵌入设备的UUID |
设备类型:设备版本 |
嵌入设备的UUID,设备类型和设备版本 |
对于每个服务:
NT |
USN |
服务类型:服务版本 |
相关设备的UUID,服务类型和服务版本 |
如果一个根设备有n个嵌入设备,m个嵌入服务,而且包含k个不同的服务类型,这将会发出3+ 2n + k次请求。这些广告消息像控制点描述了设备的所有信息。这些消息必须作为一系列一起发出,发送的顺序无关紧要,但是不能对单个消息进行刷新或取消的操作。选择一个适当的持续期是在最小化网络通讯和最大化设备状态及时更新之间求得一个平衡,相对较短的持续时间可以保证控制点在牺牲网络流量的前提下获得设备的当前状态;持续期越长可以大大减少设备刷新造成的网络流量。一般而言,设备制造商应该选择一个适当的持续时间值。
由于UDP协议是不可信的,设备应该发送多次设备发现消息。而且为了降低控制点无法收到设备或服务广告消息的可能性,设备应该定期发送它的广告消息。在设备加入网络时,它必须用NOTIFY方法发送一个多播传送请求。NOTIFY方法发送的请求没有回应消息,典型的设备通知消息格式如下:
NOTIFY * HTTP/1.1 HOST: 239.255.255.250:1900CACHE-CONTROL: max-age = seconds until advertisement expires LOCATION: URL for UPnP description for root device NT: search target NTS: ssdp:alive USN: advertisement UUID |
各HTTP协议头的含义简介:
HOST |
设置为协议保留多播地址和端口,必须是239.255.255.250:1900。 |
CACHE-CONTROL |
max-age指定通知消息存活时间,如果超过此时间间隔,控制点可以认为设备不存在 |
LOCATION |
包含根设备描述得URL地址 |
NT |
在此消息中,NT头必须为服务的服务类型。 |
NTS |
表示通知消息的子类型,必须为ssdp:alive |
USN |
表示不同服务的统一服务名,它提供了一种标识出相同类型服务的能力。 |
一个发现响应可以包含0个、1个或者多个服务类型实例。为了做出分辨,每个服务发现响应包括一个USN:根设备的标识。在同样的设备里,一个服务类型的多个实例必须用包含USN:ID的服务标识符标识出来。例如,一个灯和电源共用一个开关设备,对于开关服务的查询可能无法分辨出这是用于灯的。UPNP论坛工作组通过定义适当的设备层次以及设备和服务的类型标识分辨出服务的应用程序场景。这么做的缺点是需要依赖设备的描述URL。
3.1.2 ssdp:byebye消息
在设备和它的服务将要从网络中卸载时,设备应该对于每个未超期的ssdp:alive消息多播方式传送ssdp:byebye消息。但如果设备突然从网络卸载,它可能来不及发出这个通知消息。因此,发现消息必须在CACHE-CONTROL包含超时值,如果不重新发出广告消息,发现消息最后超时并从控制点的缓存中除去。典型的设备卸载消息格式如下:
NOTIFY * HTTP/1.1 HOST: 239.255.255.250:1900NT: search target NTS: ssdp:byebye USN: advertisement UUID各HTTP协议头的含义简介: HOST 设置为协议保留多播地址和端口,必须是239.255.255.250:1900 NT 在此消息中,NT头必须为服务的服务类型。 NTS 表示通知消息的子类型,必须为ssdp:alive USN 表示不同服务的统一服务名,它提供了一种标识出相同类型服务的能力。 |
3.2 设备查询消息
当一个控制点加入到网络中时,设备发现过程允许控制点寻找网络上感兴趣的设备。发现消息包括设备的一些特定信息或者某项服务的信息,例如它的类型、标识符、和指向XML设备描述文档的指针。从设备获得响应从本质上说,内容与多址传送的设备广播相同,只是采用单址传送方式。设备查询通过HTTP协议扩展M-SEARCH方法实现的。典型的设备查询请求消息格式:
M-SEARCH * HTTP/1.1 HOST: 239.255.255.250:1900 MAN: "ssdp:discover" MX: seconds to delay response ST: search target |
各HTTP协议头的含义简介:
HOST |
设置为协议保留多播地址和端口,必须是239.255.255.250:1900。 |
MAN |
设置协议查询的类型,必须是"ssdp:discover"。 |
MX |
设置设备响应最长等待时间,设备响应在0和这个值之间随机选择响应延迟的值。这样可以为控制点响应平衡网络负载。 |
ST |
设置服务查询的目标,它必须是下面的类型: |
在设备接收到查询请求并且查询类型(ST字段值)与此设备匹配时,设备必须向多播地址239.255.255.250:1900回应响应消息。典型:
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 |
各HTTP协议头的含义简介:
CACHE-CONTROL |
max-age指定通知消息存活时间,如果超过此时间间隔,控制点可以认为设备不存在 |
DATE |
指定响应生成的时间 |
EXT |
向控制点确认MAN头域已经被设备理解 |
LOCATION |
包含根设备描述得URL地址 |
SERVER |
饱含操作系统名,版本,产品名和产品版本信息 |
ST |
内容和意义与查询请求的相应字段相同 |
USN |
表示不同服务的统一服务名,它提供了一种标识出相同类型服务的能力。 |
在所有的发现通知中,表示UPnP根设备描述的LOCATION和统一服务名(USN)必须提供。此外,在响应消息中查询目标头(ST)必须与LOCATION和统一服务名(USN)一起提供。
专有设备或服务可以不遵循标准的UPNP模版。但如果设备或服务提供UPNP发现、描述、控制和事件过程的所有对象,它的行为就像一个标准的UPNP设备或服务。为了避免命名冲突,使用专有设备命名时除了UPNP域之外必须包含一个前缀"urn:schemas-upnp-org"。在与标准模版相同时,应该使用整数版本号。但如果与标准模版不同,不可以使用设备复用和徽标。
简单设备发现协议不提供高级的查询功能,也就是说,不能完成某个具有某种服务的设备这样的复合查询。在完成设备或者服务发现之后,控制点可以通过设备或服务描述的URL地址完成更为精确的信息查询。