概述
前言
做android智能硬件开发一年,蓝牙接触多的就是spp模拟串口通信,而更多的是upnp,因为大部分的项目都是基于cling库的wifi方案的项目。设备的wifi方案相对于蓝牙方案,传输速度快,覆盖范围广,能够脱离设备独立联网,协议规范简单明了,但价格相对要高一些。
cling库地址:
http://4thline.org/projects/cling/
UPnP简介
upnp是 universal plug and play,即:即插即用设备,可以当作是一个相对复杂的网络协议,毕竟它包含了很多其他的网络协议,如:ip(设备寻址),tcp、udp(数据打包发送)、http(数据传递格式)等。
upnp可以扩展,也就是说你还可以在启动加入其他的协议,比如:传递数据时,http协议再包一层json协议,或者数据传递使用xml协议来传递等等。
upnp之所以强大,感觉很大一个原因是基于互联网,这样对等设备可以通过互联网自由交互,也就是说任何可以联网的设备都可以使用upnp协议。
UPnP工作步骤
有兴趣的可以去看看这个upnp文档:
英文版ppt介绍:
http://101.96.10.63/trinea.github.io/doc/upnp/UPnP_UDA_tutorial_July2014.pdf
中文版文档介绍:
http://read.pudn.com/downloads37/doc/comm/125876/UDA1.0-ChinesePDF.pdf
工作步骤其实只是一个工作的逻辑,大概的按功能划分为6个步骤,如下图1所示:
工作流程如下图2所示:
0、寻址-Addressing
既然基于互联网,那么基本的p2p协议需要满足,所以寻址算是upnp的基础。
所以就必须要有寻址,寻址的过程就是设备获取ip地址的过程,这个里面一般都使用DHCP(Dynamic Host Configuration Protocol,动态主机配置协议),即路由动态的分配一个没有使用的ip地址给设备。
1、发现-Discovery
既然来到了互联网的大世界,通过寻址有了身份标识ip,闲的无聊那么必然就要找个小伙伴交流沟通,当然最好是妹子,所以这时候就有了一个发现的概念。
首先你要先自我介绍,也就是网络中的控制点介绍自己(是什么、能干什么),因为不知道当前世界有多少个控制点,所以一般通过喊话的形式来介绍自己。也就是说新加入的设备以多播的形式广播自己的信息。
当然如果作为一个控制点,也有权限搜索自己感兴趣的设备。搜的时候控制点自己不知道有没有自己感兴趣的设备。同样这也是通过多播的形式,当世界的另一端乖妹子听到了这个信息,那么就会以单独的形式应答,这就是单播响应。就相当于面试一样,公司要找一个美工妹子,发布一个广告,添加要求福利待遇,然后留个邮箱,感兴趣的美工妹子们就会发简历到这个邮箱
。人可以喊,公司可以登招聘广告,但是设备不可以。那么设备是怎么做到的,设备是依托于ssdp(Simple Service Discovery Protocol)简单服务发现协议,这个协议类似定义了怎么喊,喊的格式,怎么登招聘广告,广告的格式是怎么样的。如下所示:
- 设备介绍自己(喊话介绍自己格式)
NOTIFY * HTTP/1.1 (标准的http1.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 复合标识符
其中特别说明的是LOCATION,LOCATION是关于设备更多信息的 URL 地址(或有关服务的内含设备),这也就是描叙设备信息的一个文档地址,后面会用到。
- 控制点搜索(公司发布招聘广告格式)
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900(路由固定的多播地址和端口 互联网编号分配组织很强势的定义好了的)
MAN: "ssdp:discover"
MX: seconds to delay response
ST: search target
这里需要注意的是ssdp其实包含两个简单协议,即:HTTPMU、HTTPU。HTTPMU(Http Multicast UDP)是http协议的变种,即通过udp的方式组播发送http格式的内容,HTTPU即通过udp的方式发送单播给host。
2、描述-Description
既然有了寻找小伙伴的方式,那么怎么挑选小伙伴呢?发现直接能得到的只有一些简单的标识信息,如设备(或服务)的 UPnP 类型、设备的全球唯一标识符和设备 UPnP 描述的 URL 地址。而要了解一个小伙伴当然是不够的,就相当于招聘光靠简历个人简介是完全不够了,还需要了解他的长相身材,工作能力以及性格价值观等
。
所以就需要获取设备描述,那么怎么获取呢?对的,怎么获取,其实在设备发现的时候就已经把设备描述带出来了,只是封装在一个url中,也就是LOCATION中的描述url,通过location中的url能获取一个xml,一般设备的描述都是通过xml来标识的。
设备描述一般包含两个部分:描述所包含的物理与逻辑设备、一个或多个服务描述(描述设备对外暴露的能力)。也就相当于物体除了基本的外观名称以外,还包括他能干什么
。设备描述包括特定厂商、制造商信息,如模块名称和编号、序列号、制造商名称、特定厂商网站 URL 等(详细信息如下)。对于设备中的每种服务,设备描述都包含服务类型、名称、服务描述 URL、控制 URL 以及事件 URL。设备描述还包含所有嵌入式设备描述与 URL 地址集。
如下所示:
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>base URL for all relative URLs</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:deviceType:v</deviceType>
<friendlyName>short user-friendly title</friendlyName>
<manufacturer>manufacturer name</manufacturer>
<manufacturerURL>URL to manufacturer site</manufacturerURL>
<modelDescription>long user-friendly title</modelDescription>
<modelName>model name</modelName>
<modelNumber>model number</modelNumber>
<modelURL>URL to model site</modelURL>
<serialNumber>manufacturer's serial number</serialNumber>
<UDN>uuid:UUID</UDN>
<UPC>Universal Product Code</UPC>
<iconList>
<icon>
<mimetype>image/format</mimetype>
<width>horizontal pixels</width>
<height>vertical pixels</height>
<depth>color depth</depth>
<url>URL to icon</url>
</icon>
XML to declare other icons, if any, go here
</iconList>
<!--以上是信息描叙,以下是能力行为描叙-->
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:serviceType:v</serviceType>
<serviceId>urn:upnp-org:serviceId:serviceID</serviceId>
<SCPDURL>URL to service description</SCPDURL>
<controlURL>URL for control</controlURL>
<eventSubURL>URL for eventing</eventSubURL>
</service>
Declarations for other services defined by a UPnP Forum working committee (if any)
go here
Declarations for other services added by UPnP vendor (if any) go here
</serviceList>
<!--以上是能力行为描叙,以下是从设备描述-->
<deviceList>
Description of embedded devices defined by a UPnP Forum working committee (if any)
go here
Description of embedded devices added by UPnP vendor (if any) go here
</deviceList>
<presentationURL>URL for presentation</presentationURL>
</device>
</root>
这里需要值得注意的是:能力行为的描述
也就是:
<service>
<serviceType>urn:schemas-upnp-org:service:serviceType:v</serviceType>
<serviceId>urn:upnp-org:serviceId:serviceID</serviceId>
<SCPDURL>URL to service description</SCPDURL>
<controlURL>URL for control</controlURL>
<eventSubURL>URL for eventing</eventSubURL>
</service>
- serviceType
描述UPnP 服务类型,固定格式:urn:domain-name:service:serviceType:v - serviceId
服务标识符,固定格式urn:domain-name:serviceId:serviceID,一般应用中访问就需要通过serviceId来调用相关的服务 - SCPDURL
服务描述的 URL,url中细节描述了服务包含的action,参数等。后面控制订阅都需要用到。 - controlURL
控制的 URL,调用服务的action必须要通过这个url来调用,就相当于一个控制服务的地址 - eventSubURL
事件的 URL,如果服务没有事件,则该元素必须展示出来,但是应该为空。
下面看看标准SCPDURL中的内容:
<?xml version="1.0"?>
<scpd xmlns="urn:schemas-UPnP-org:service-1-0">
<!--要求upnp的架构版本-->
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<!--action列表-->
<actionList>
<action>
<!--action名称-->
<name>actionName</name>
<!--参数列表-->
<argumentList>
<argument>
<!--参数名称-->
<name>formalParameterName</name>
<!--参数是入参还是出参-->
<direction>in xor out</direction>
<retval />
<!--必须是一个状态变量的名称,文档后面状态变量的表会对应其类型和取值范围等,就类似类中的某个属性值的名称-->
<relatedStateVariable>stateVariableName</relatedStateVariable>
</argument>
</argumentList>
</actionList>
<!--状态变量的表-->
<serviceStateTable>
<!--sendEvents标识变量值发生变化需不需要回调通知状态改变-->
<stateVariable sendEvents="yes">
<!--状态变量的名称-->
<name>variableName</name>
<!--状态变量的数据类型-->
<dataType>variable data type</dataType>
<!--状态变量的初始化的值-->
<defaultValue>default value</defaultValue>
<!--状态变量的允许设置的值-->
<allowedValueList>
<allowedValue>enumerated value</allowedValue>
Other allowed values defined by UPnP Forum working committee (if any) go here
</allowedValueList>
</stateVariable>
<stateVariable sendEvents="yes">
<name>variableName</name>
<dataType>variable data type</dataType>
<defaultValue>default value</defaultValue>
<!--状态变量的允许设置的值范围-->
<allowedValueRange>
<minimum>minimum value</minimum>
<maximum>maximum value</maximum>
<step>increment value</step>
</allowedValueRange>
</stateVariable>
Declarations for other state variables defined by UPnP Forum working committee
(if any) go here
Declarations for other state variables added by UPnP vendor (if any) go here
</serviceStateTable>
</scpd>
在实际使用当中,service就相当于一个类,状态变量就相当于类的全局变量,一定别订阅,发生变化就要通知订阅者更新,而service中对应的action就相当于类中的方法。
3、控制-Control
既然有了身份标识,发现了小伙伴,那么控制就自然而然很重要了。其实控制就相当于领导和你沟通工作,让你干啥,你干完了给领导个反馈。
那么控制是怎么实现的呢?一个控制的过程包含 控制地址、控制说明、控制执行、控制响应。
- 控制地址
发送控制命令,首先得有控制的地址,所以描述中的control url就是需要的控制地址,相当于你找到你的新玩具的控制开关的模块。
- 控制说明
找到了控制模块那么你需要知道怎么控制,这时候你就需要说明书了,而对于设备,描述中的scpd url,就详细表明了设备提供的功能和操作步骤。
- 控制执行
阅读完说明书,那么就需要你执行命令了。设备命令的执行传递依托于tcp/ip协议,而内容的封装在http协议中,但是http协议的内容光做展示可能比较合适,但是做命令的封装可能就相对较弱,所以upnp在http中增加了标准的交换数据的一种协议 soap(简单对象访问协议),soap协议简单、轻量、而且是基于xml协议的,所以内容格式可以看出是xml的语法结构,下面就看看具体的参考报文格式:
POST path of control URL HTTP/1.1
HOST: host of control URL:port of 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>
other in args and their values go here, if any
</u:actionName>
</s:Body>
</s:Envelope>
关于soap协议的介绍可以参考 w3c
soap教程
- 控制响应
每个控制都需要有回应,就相当于你去播放cd一样,如果你执行了播放命令,没有声音播放,你会感觉很奇怪,会思考是不是音量太小或者坏叼了。所以一个控制命令执行后没有控制的响应也就不清楚命令执行的状况。下面看看标准的控制响应的报文:
HTTP/1.1 200 OK
CONTENT-LENGTH: bytes in body
CONTENT-TYPE: text/xml; charset="utf-8"
DATE: when response was generated
EXT:
SERVER: OS/version UPnP/1.0 product/version
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:actionNameResponse xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
<argumentName>out arg value</argumentName>
other out args and their values go here, if any
</u:actionNameResponse>
</s:Body>
</s:Envelope>
4、事件-Eventing
事件即设备的状态量发生了变化,使用观察者模式,首先观察某个状态量就需要注册一个观察者,当状态量发生变化的时候,设备就会提示观察者状态量发生变化,请及时处理,有关于观察者可以去看看著名的气象局的例子
,在upnp协议中事件协议是用的是GENA协议(Generic Event Notification Architecture)。下面是报文格式。
- 订阅事件
SUBSCRIBE publisher path HTTP/1.1
HOST: publisher host:publisher port
CALLBACK: <delivery URL>
NT: upnp:event
TIMEOUT: Second-requested subscription duration
- 取消订阅
UNSUBSCRIBE publisher path HTTP/1.1
HOST: publisher host:publisher port
SID: uuid:subscription UUID
- 消息订阅
NOTIFY delivery path HTTP/1.1
HOST: delivery host:delivery port
CONTENT-TYPE: text/xml
CONTENT-LENGTH: Bytes in body
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>
5、展示-Presentation
展示作为一个控制和事件的补充,实现upnp协议并不强制要求。其实就是一个网页,可以看到设备的信息和状态,做的好的还可以对设备进行控制
。如果提供的完整的话就可以不需要什么应用,一个网页就可以查看设备的基本信息,控制设备的基本操作。
UPnP总结
上面详细的说明了upnp的协议的介绍,其实用一个图就可以全部概括起来,如下图3:
寻址
UPnP 网络互连的基础是基于DHCP或AutoIP的 IP 寻址。这也是p2p协议的基础,就相当于获取身份标识的ID(身份 证)。
发现
如果获取了一个 IP 地址,则 UPnP 网络的第 1 步是发现。在将一个设备添加到网络上之后,UPnP 发现协议允许该设备向网络中的控制点宣告其服务。同样,当一个控制点被添加到网络后,UPnP 发现协议允许该控制点在网上搜索
感兴趣的设备。这两者处理上都需要HTTPMU协议支持。ssdp协议是支撑发现的基础。描述
UPnP 网络中的第 2 步是描述。控制点在发现一个设备之后仍然对其知之甚少。为了使控制点了解到更多关于设备及其能力的信息或与设备进行交互,则控制点必须取得来自该设备在发现消息中所提供之 URL 的设备描述。描述的基础是发现,如果没有发现获取到设备的最基础的信息,得不到location中的设备描述url,也就没有设备能力这一说。控制
UPnP 网络中的第 3 步是控制。当一个控制点取得设备描述后,该控制点可将动作发至一个设备的服务。为此,控制点将一条适当的控制消息发至服务的控制 URL(在设备描述中提供)。控制消息同样利用简单对象访问协议(SOAP)通过 XML 来表达。事件
UPnP 网络的第 4 步是事件触发。针对服务的 UPnP 描述包括一个服务响应的动作列表,以及一个对服务器运行时状态进行展示的变量列表。在这些变量变更时服务会发布更新,一个控制点可以预订接收此信息。服务通过发送事件消息来发布更新。事件消息包含一个或多个状态变量名和这些变量的当前值。这些消息同样通过 XML 来表达,并采用通用事件通知架构(GENA)格式。展示
UPnP 网络中的第 5 步是展示。如果设备有用于展示的 URL,那么控制点就可以通过此 URL 取得一个页面,在浏览器中加载该页面,并且根据页面的功能,支持用户控制设备和/或浏览设备状态。每一项完成的程度取决于展示页面
和设备的具体功能。
其实cling库upnp协议的实现,框架本身就是通过代码来提供报文格式的封装,使用者能够动态确定设备交互报文的内容。有时间分享一下cling的源码分析。
最后
以上就是称心猎豹为你收集整理的UPnP的介绍和理解的全部内容,希望文章能够帮你解决UPnP的介绍和理解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复