日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UPNP(一)

發(fā)布時間:2023/12/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UPNP(一) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://antkillerfarm.github.io/

概述

官方的協(xié)議規(guī)范參見:

http://www.upnp.org/specs/

上圖是UPNP的協(xié)議棧。詳細(xì)的解釋參見:

http://www.h3c.com.cn/MiniSite/Technology_Circle/Net_Reptile/The_Five/Home/Catalog/201206/747039_97665_0.htm

這是H3C的一個系列教程中的一篇。

libupnp

libupnp是UPNP協(xié)議的一個實(shí)現(xiàn)庫。它最早由英特爾開發(fā)并開源,是目前Linux平臺最流行的實(shí)現(xiàn)庫,其官網(wǎng)為:

http://pupnp.sourceforge.net/

和一般的Linux應(yīng)用庫不同,libupnp沒有采用搭積木的方式構(gòu)建庫,而是自己集成了HTTP處理、XML處理、HTTP服務(wù)器、線程池等功能(當(dāng)然,這些功能做的都比較簡單,是個理想的教材庫)。估計(jì)這與它的跨平臺目標(biāo)有關(guān)。

安裝方法:

sudo apt-get install libupnp-dev

上圖是libupnp體系結(jié)構(gòu)圖,其參考教程可參見:

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

這里僅對上文中的內(nèi)容,做一個補(bǔ)充:

1.GENA協(xié)議規(guī)范

https://tools.ietf.org/id/draft-cohen-gena-p-base-01.txt

2.其他參考資料

http://max.book118.com/html/2014/0811/9385832.shtm

http://blog.csdn.net/hqyhqyhq/article/details/17921797

http://download.csdn.net/detail/liguangshou06/2685789

libupnp示例詳解

libupnp自帶的示例在upnp/sample路徑下。編譯之后,可生成三個可執(zhí)行文件:

1.tv_device。UPNP設(shè)備端實(shí)現(xiàn),即UPNP的服務(wù)提供者。

2.tv_ctrlpt。UPNP控制端實(shí)現(xiàn)。

3.tv_combo。前兩者的混合體。

實(shí)際測試使用中,可以同時運(yùn)行tv_ctrlpt和tv_device,以觀察兩者之間的交互。

tv_device代碼流程詳解

初始化

upnp/sample/linux/tv_device_main.c: main

upnp/sample/common/tv_device.c: device_main

upnp/sample/common/tv_device.c: TvDeviceStart

upnp/src/api/upnpapi.c: UpnpInit

upnp/src/api/upnpapi.c: UpnpInitStartServers

upnp/src/genlib/miniserver/miniserver.c: StartMiniServer

這是整個初始化過程中,最重要的函數(shù)。它負(fù)責(zé)創(chuàng)建Web Server和線程池。UPNP的所有功能都在這些線程(而不是主線程)中實(shí)現(xiàn)。

事件處理

事件處理分成兩步

1.注冊事件處理回調(diào)函數(shù)

upnp/src/api/upnpapi.c: TvDeviceStart

upnp/src/api/upnpapi.c: UpnpRegisterRootDevice

這一步向一個中間結(jié)構(gòu)注冊回調(diào)函數(shù)。

upnp/src/api/upnpapi.c: UpnpInitPreamble

這一步調(diào)用SetGenaCallback函數(shù),將上一步注冊到中間結(jié)構(gòu)中的回調(diào)函數(shù),注冊到GENA事件處理線程中。

UpnpRegisterRootDevice有若干不同的變種:UpnpRegisterRootDevice2、UpnpRegisterRootDevice3、UpnpRegisterRootDevice4。其中,對于動態(tài)生成設(shè)備描述的方式來說,UpnpRegisterRootDevice2更好用一些。

2.事件處理流程

upnp/src/genlib/miniserver/miniserver.c: RunMiniServer

upnp/src/genlib/miniserver/miniserver.c: web_server_accept

upnp/src/genlib/miniserver/miniserver.c: schedule_request_job

這一步從線程池中啟動一個線程來處理事件。

upnp/src/genlib/miniserver/miniserver.c: handle_request

upnp/src/genlib/miniserver/miniserver.c: dispatch_request

這一步根據(jù)事件類型進(jìn)行分發(fā)。具體到GENA就是調(diào)用:

upnp/src/gena/gena_callback2.c: genaCallback

這一步根據(jù)角色的不同,調(diào)用gena_process_subscription_request(device)或gena_process_notification_event(control point)。

upnp/src/gena/gena_device.c: gena_process_subscription_request

這里會最終調(diào)用注冊的事件處理函數(shù)。

交互流程

1.設(shè)備發(fā)現(xiàn)

設(shè)備發(fā)現(xiàn)過程使用SSDP協(xié)議,其端口為:

#define SSDP_PORT 1900

1)主動告知

報(bào)文:

NOTIFY * HTTP/1.1 NTS: ssdp:alive

函數(shù)調(diào)用:

upnp/src/genlib/miniserver/miniserver.c: RunMiniServer

upnp/src/genlib/miniserver/miniserver.c: ssdp_read

upnp/src/ssdp/ssdp_server.c: readFromSSDPSocket

upnp/src/ssdp/ssdp_server.c: ssdp_event_handler_thread

upnp/src/ssdp/ssdp_device.c: ssdp_handle_device_request

upnp/src/ssdp/ssdp_device.c: advertiseAndReplyThread

upnp/src/ssdp/ssdp_server.c: AdvertiseAndReply

upnp/src/ssdp/ssdp_device.c: DeviceAdvertisement

upnp/src/ssdp/ssdp_device.c: CreateServicePacket msg_type=MSGTYPE_ADVERTISEMENT

2)查詢消息

報(bào)文:

M-SEARCH * HTTP/1.1 MAN: ssdp:discover

函數(shù)調(diào)用:

upnp/sample/common/tv_ctrlpt.c: TvCtrlPointCommandLoop

upnp/sample/common/tv_ctrlpt.c: TvCtrlPointProcessCommand

upnp/sample/common/tv_ctrlpt.c: TvCtrlPointRefresh

upnp/src/api/upnpapi.c: UpnpSearchAsync

upnp/src/ssdp/ssdp_ctrlpt.c: SearchByTarget

upnp/src/ssdp/ssdp_ctrlpt.c: CreateClientRequestPacket

3)再見消息

報(bào)文:

NOTIFY * HTTP/1.1 NTS: ssdp:byebye

函數(shù)調(diào)用:

從RunMiniServer到DeviceAdvertisement的步驟和主動告知相同。

upnp/src/ssdp/ssdp_device.c: CreateServicePacket msg_type=MSGTYPE_SHUTDOWN

4)添加設(shè)備、服務(wù)

upnp/sample/common/tv_ctrlpt.c: TvCtrlPointCallbackEventHandler

upnp/sample/common/tv_ctrlpt.c: TvCtrlPointAddDevice

upnp/sample/common/sample_util.c: SampleUtil_FindAndParseService

輔助函數(shù)

upnp/sample/common/sample_util.c: SampleUtil_PrintEvent

這是個事件打印函數(shù),對于分析UPNP的交互流程很有幫助。

threadutil/src/ThreadPool.c: TPJobXXX

這是一系列和線程池操作相關(guān)的函數(shù)。

upnp/src/uuid/uuid.c: uuid_create

生成UUID的函數(shù)。

upnp/src/api/UpnpString.c

這個文件中,有個String的C語言實(shí)現(xiàn),代碼寫得不錯。

tv_ctrlpt代碼流程詳解

1.初始化

upnp/sample/linux/tv_ctrlpt_main.c: main

common/tv_ctrlpt.c: TvCtrlPointStart

upnp/src/api/upnpapi.c: UpnpInit

以下與tv_device相同。

2.注冊客戶端

common/tv_ctrlpt.c: TvCtrlPointStart

upnp/src/api/upnpapi.c: UpnpRegisterClient

其他部分與tv_device注冊事件的流程相同。

common/tv_ctrlpt.c: TvCtrlPointCallbackEventHandler

這是tv_ctrlpt的事件處理函數(shù)。

gmediarender的UPNP流程詳解

gmediarender使用libupnp庫進(jìn)行DLNA協(xié)議的交互。這個項(xiàng)目的難度中等,可作為libupnp庫的進(jìn)階教程。由于大部分的內(nèi)容和tv_device類似,因此,這里只列出差異的部分。

概述

MediaRenderer包含三個服務(wù):

1)RenderingControl。代碼在src/upnp_control.c中。

2)ConnectionManager。代碼在src/upnp_connmgr.c中。

3)AVTransport。代碼在src/upnp_transport.c中。

注意:MediaRenderer和所包含的服務(wù)都有版本的概念。比如MediaRenderer在XML中一般表示為urn:schemas-upnp-org:device:MediaRenderer:1,其中最后的數(shù)字1就是版本號。

此外,MediaRenderer的版本和所包含服務(wù)的版本,有一定的對應(yīng)關(guān)系。比如MediaServer:4中的ScheduledRecording:2。因?yàn)镾cheduledRecording是在MediaServer:2中引入的,因此它的版本號就不可能和MediaServer的版本號一致。MediaRenderer也是一樣的情況。

一個服務(wù)可以提供若干功能。這些功能主要包括三方面:

1.狀態(tài)變量(State Variables)。狀態(tài)變量可以進(jìn)行查詢操作。

2.動作(Action)。get類的Action可以實(shí)現(xiàn)和查詢狀態(tài)變量類似的效果,但比后者要復(fù)雜一些。

3.事件(Eveting)。事件是設(shè)備(Device)主動推送給控制點(diǎn)(Control Point)的消息,需要后者訂閱(SUBSCRIBE)或退訂(UNSUBSCRIBE)。

初始化

src/main.c: main

src/upnp_device.c: upnp_device_init

src/upnp_device.c: initialize_device

upnp/src/api/upnpapi.c: UpnpInit

動作(Action)處理

1.數(shù)據(jù)結(jié)構(gòu)

相關(guān)數(shù)據(jù)結(jié)構(gòu)按從大到小的順序,依次為:

服務(wù)->動作->參數(shù)->值類型->基本數(shù)據(jù)類型

這里從最小的基本數(shù)據(jù)類型說起。由于MediaRenderer的三個服務(wù)在這里的細(xì)節(jié)都是類似的,因此下面僅以RenderingControl為例。

1)基本數(shù)據(jù)類型

src/upnp.h: param_datatype定義了可用的基本數(shù)據(jù)類型,比如STRING、BOOLEAN、I2、I4、UI2、UI4等。后四種都是整數(shù)類型,I表示整數(shù),U表示無符號,2表示2個字節(jié)的寬度。

2)值類型

src/upnp.h: var_meta定義了值類型的數(shù)據(jù)結(jié)構(gòu)。該類型的實(shí)例是src/upnp_control.c: control_var_meta。var_meta的sendevents成員的含義是,如果該值發(fā)生改變時,發(fā)送消息則設(shè)置為SENDEVENT_YES(默認(rèn)值),否則設(shè)為SENDEVENT_NO。

3)參數(shù)

src/upnp.h: argument定義了參數(shù)的數(shù)據(jù)結(jié)構(gòu)。典型示例如下:

{ "InstanceID", PARAM_DIR_IN, CONTROL_VAR_AAT_INSTANCE_ID }

3)動作

一個動作包含若干參數(shù),因此動作的數(shù)據(jù)結(jié)構(gòu)是一個argument數(shù)組。以SetVolume動作為例,它的參數(shù)結(jié)構(gòu)的實(shí)例為src/upnp_control.c: arguments_set_vol。

4)服務(wù)

一個服務(wù)包含若干動作,因此服務(wù)的數(shù)據(jù)結(jié)構(gòu)是一個argument的二維數(shù)組。在這里是src/upnp_control.c: argument_list。

服務(wù)不僅包含動作,還包含了其他一些東西,這些都被統(tǒng)一組織到src/upnp.h: service結(jié)構(gòu)中。該結(jié)構(gòu)的實(shí)例是src/upnp_control.c: control_service_。

功能發(fā)布

功能發(fā)布用于向外界宣布本服務(wù)所支持的功能。

gmediarender功能發(fā)布的內(nèi)容是動態(tài)生成的,其函數(shù)為:src/upnp.c: gen_scpd

事件處理

src/upnp_device.c: event_handler

返回值處理

src/upnp_device.h: upnp_add_response

調(diào)用這個函數(shù)或者它的派生函數(shù),生成返回值的xml。

狀態(tài)變量處理

gmediarender定義了一個變量容器來維護(hù)相關(guān)的狀態(tài)變量。這個容器的代碼在src/variable-container.c中。

代碼中用的比較多的是replace_var和get_var這兩個進(jìn)一步封裝后的接口函數(shù)。

播放處理

gmediarender的播放處理代碼在src/output_gstreamer.c中。其中最關(guān)鍵的結(jié)構(gòu)是output_module。

gmediarender的URI主要有兩個即uri和next_uri。在pipeline的about-to-finish事件中,會做相應(yīng)的處理。

gmediaserver

除了gmediarender項(xiàng)目之外,GNU還有個名叫g(shù)mediaserver的項(xiàng)目,也是使用libupnp庫,結(jié)構(gòu)和gmediarender十分相似,它的官網(wǎng)是:

http://www.nongnu.org/gmediaserver/

自制的Control Point示例

概述

和gmediarender相比,libupnp的sample寫的并不好。這主要體現(xiàn)在以下方面:

1.封裝的層次太多。雖然這樣一來,main函數(shù)看起來很簡單,細(xì)節(jié)都被隱藏了起來。但隱藏的先決條件,是對用戶使用的透明。而sample顯然做不到這一點(diǎn),于是,用戶擴(kuò)展業(yè)務(wù)功能的時候,還要翻越層層封裝,才能找到需要修改的地方。

2.使用不方便。設(shè)備功能的XML描述文件居然是寫死的,擴(kuò)展極為不易。(gmediarender的XML描述文件是動態(tài)生成的。)

針對這些問題,我打算模仿gmediarender的寫法,做一個Control Point的示例。

其代碼重構(gòu)的核心是:將用戶需要擴(kuò)展的業(yè)務(wù)功能,抽象為數(shù)據(jù)結(jié)構(gòu),并將這些數(shù)據(jù)結(jié)構(gòu)的內(nèi)容定義放在一起,以便于用戶的修改。換句話說,用戶只需要修改數(shù)組的內(nèi)容,而不必修改代碼,即可擴(kuò)展業(yè)務(wù)功能。

在功能上,為了使這個示例更有意義,這里選擇gmediarender作為和示例配套的Device程序。因?yàn)?#xff0c;gmediarender實(shí)現(xiàn)的是一個有實(shí)用價值的協(xié)議規(guī)范,而非demo,所需處理的情況也比demo復(fù)雜的多。

Step 1

這次,我打算從頭開始搭建Control Point示例。也就是從main函數(shù)出發(fā),逐步完善相關(guān)功能。這一步的代碼在:

https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/helloworld/upnp/step1

該程序主要實(shí)現(xiàn):

1.基本框架。包括初始化和注冊Control Point。

2.通過SSDP的搜索功能,搜索網(wǎng)絡(luò)設(shè)備。

Step 2

這一步的代碼在:

https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/helloworld/upnp/step2

總結(jié)

以上是生活随笔為你收集整理的UPNP(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。