做android智能硬件开发一年,蓝牙接触多的就是spp模拟串口通信,而更多的是upnp,因为大部分的项目都是基于cling库的wifi方案的项目。设备的wifi方案相对于蓝牙方案,传输速度快,覆盖范围广,能够脱离设备独立联网,协议规范简单明了,但价格相对要高一些。
cling库地址:
http://4thline.org/projects/cling/
upnp是 universal plug and play,即:即插即用设备,可以当作是一个相对复杂的网络协议,毕竟它包含了很多其他的网络协议,如:ip(设备寻址),tcp、udp(数据打包发送)、http(数据传递格式)等。
upnp可以扩展,也就是说你还可以在启动加入其他的协议,比如:传递数据时,http协议再包一层json协议,或者数据传递使用xml协议来传递等等。
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所示:
既然基于互联网,那么基本的p2p协议需要满足,所以寻址算是upnp的基础。
所以就必须要有寻址,寻址的过程就是设备获取ip地址的过程,这个里面一般都使用DHCP(Dynamic Host Configuration Protocol,动态主机配置协议),即路由动态的分配一个没有使用的ip地址给设备。
既然来到了互联网的大世界,通过寻址有了身份标识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。
既然有了寻找小伙伴的方式,那么怎么挑选小伙伴呢?发现直接能得到的只有一些简单的标识信息,如设备(或服务)的 UPnP 类型、设备的全球唯一标识符和设备 UPnP 描述的 URL 地址。而要了解一个小伙伴当然是不够的,就相当于招聘光靠简历个人简介是完全不够了,还需要了解他的长相身材,工作能力以及性格价值观等
。
所以就需要获取设备描述,那么怎么获取呢?对的,怎么获取,其实在设备发现的时候就已经把设备描述带出来了,只是封装在一个url中,也就是LOCATION中的描述url,通过location中的url能获取一个xml,一般设备的描述都是通过xml来标识的。
设备描述一般包含两个部分:描述所包含的物理与逻辑设备、一个或多个服务描述(描述设备对外暴露的能力)。也就相当于物体除了基本的外观名称以外,还包括他能干什么
。设备描述包括特定厂商、制造商信息,如模块名称和编号、序列号、制造商名称、特定厂商网站 URL 等(详细信息如下)。对于设备中的每种服务,设备描述都包含服务类型、名称、服务描述 URL、控制 URL 以及事件 URL。设备描述还包含所有嵌入式设备描述与 URL 地址集。
如下所示:
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1major>
<minor>0minor>
specVersion>
<URLBase>base URL for all relative URLsURLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:deviceType:vdeviceType>
<friendlyName>short user-friendly titlefriendlyName>
<manufacturer>manufacturer namemanufacturer>
<manufacturerURL>URL to manufacturer sitemanufacturerURL>
<modelDescription>long user-friendly titlemodelDescription>
<modelName>model namemodelName>
<modelNumber>model numbermodelNumber>
<modelURL>URL to model sitemodelURL>
<serialNumber>manufacturer's serial numberserialNumber>
<UDN>uuid:UUIDUDN>
<UPC>Universal Product CodeUPC>
<iconList>
<icon>
<mimetype>image/formatmimetype>
<width>horizontal pixelswidth>
<height>vertical pixelsheight>
<depth>color depthdepth>
<url>URL to iconurl>
icon>
XML to declare other icons, if any, go here
iconList>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:serviceType:vserviceType>
<serviceId>urn:upnp-org:serviceId:serviceIDserviceId>
<SCPDURL>URL to service descriptionSCPDURL>
<controlURL>URL for controlcontrolURL>
<eventSubURL>URL for eventingeventSubURL>
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 presentationpresentationURL>
device>
root>
这里需要值得注意的是:能力行为的描述
也就是:
<service>
<serviceType>urn:schemas-upnp-org:service:serviceType:vserviceType>
<serviceId>urn:upnp-org:serviceId:serviceIDserviceId>
<SCPDURL>URL to service descriptionSCPDURL>
<controlURL>URL for controlcontrolURL>
<eventSubURL>URL for eventingeventSubURL>
service>
下面看看标准SCPDURL中的内容:
<scpd xmlns="urn:schemas-UPnP-org:service-1-0">
<specVersion>
<major>1major>
<minor>0minor>
specVersion>
<actionList>
<action>
<name>actionNamename>
<argumentList>
<argument>
<name>formalParameterNamename>
<direction>in xor outdirection>
<retval />
<relatedStateVariable>stateVariableNamerelatedStateVariable>
argument>
argumentList>
actionList>
<serviceStateTable>
<stateVariable sendEvents="yes">
<name>variableNamename>
<dataType>variable data typedataType>
<defaultValue>default valuedefaultValue>
<allowedValueList>
<allowedValue>enumerated valueallowedValue>
Other allowed values defined by UPnP Forum working committee (if any) go here
allowedValueList>
stateVariable>
<stateVariable sendEvents="yes">
<name>variableNamename>
<dataType>variable data typedataType>
<defaultValue>default valuedefaultValue>
<allowedValueRange>
<minimum>minimum valueminimum>
<maximum>maximum valuemaximum>
<step>increment valuestep>
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就相当于类中的方法。
既然有了身份标识,发现了小伙伴,那么控制就自然而然很重要了。其实控制就相当于领导和你沟通工作,让你干啥,你干完了给领导个反馈。
那么控制是怎么实现的呢?一个控制的过程包含 控制地址、控制说明、控制执行、控制响应。
发送控制命令,首先得有控制的地址,所以描述中的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"
"http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
"urn:schemas-upnp-org:service:serviceType:v">
in arg value
other in args and their values go here, if any
关于soap协议的介绍可以参考 w3c
soap教程
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
"http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
Body>
"urn:schemas-upnp-org:service:serviceType:v">
out arg value
other out args and their values go here, if any
Body>
事件即设备的状态量发生了变化,使用观察者模式,首先观察某个状态量就需要注册一个观察者,当状态量发生变化的时候,设备就会提示观察者状态量发生变化,请及时处理,有关于观察者可以去看看著名的气象局的例子
,在upnp协议中事件协议是用的是GENA协议(Generic Event Notification Architecture)。下面是报文格式。
SUBSCRIBE publisher path HTTP/1.1
HOST: publisher host:publisher port
CALLBACK:
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
"urn:schemas-upnp-org:event-1-0">
property>
new value
property>
Other variable names and values (if any) go here.
展示作为一个控制和事件的补充,实现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的源码分析。