用 Sqlite 實現此 Media NAS 系統後,系統運行性能高,而且程序也具有很好的跨平台性。
此 Media NAS 服務系統是基於通用即插即用(UPnP)協議的系統。
網絡附屬存儲(NAS:Network Attached Storage)設備是一種專用數據存儲設備,它以數據為中心,其上存儲了大量的視頻、音頻、圖象文件。NAS 服務器本身對數據有較好存儲、保護機制,從而保證其提供多媒體服務的穩定性。為了便於對其上的海量媒體文件的有效共享,我們使用了 UpnP 協議來作為網絡訪問協議。
UpnP 網絡系統是針對智能家電、無線設備以及個人電腦網絡連接而設計的一種架構。它旨在為家庭、小型企業、公共場所中的網絡提供易於使用、靈活且基於標准的連接。UpnP 是一個充分利用 TCP/IP 和 Web 技術的分布式開放型網絡體系結構,除能夠在家中、辦公室和公共場所聯網設備之間的完整控制和數據傳輸之外,還可建立無縫緊密的連接網絡。
UpnP 設備的特點是它不需要使用設備驅動程序,取而代之的是通用協議,一個設備就是一個完整的小系統,直接通過網口將其接入 UpnP 網絡中即可。UpnP 網絡不依賴於任何特定的操作系統、編程語言或物理媒體。UPnP 並未指定應用程序應該使用哪種 API(應用程序接口),UpnP 裝置開發者可以按用戶的需求創建自己的 API。UpnP 設備可以在任何操作系統上采用任何編程語言來實現。這就意味著,一台設備能夠動態加入一個網絡,獲取一個 IP 地址,"零"配置,即插即用,它自動通報其能提供的功能服務,以及了解其它設備的存在和功能。在 UpnP 網絡中的設備都向外提供自身服務的描述,外部其他設備通過調用這些服務來控制這些 UpnP 設備。
UpnP 充分利用了包括 IP、TCP、UDP、HTTP 和 XML 在內的互聯網組件。它以 XML 來表達內容,並通過HTTP 進行傳輸。在 UpnP 網絡中的消息通過采用簡單服務發現協議(SSDP)、通用事件通知架構(GENA)和簡單對象訪問協議(SOAP)來進行格式化。然後消息通過運行於 UDP 上的多播或單播類 HTTP,或是運行於TCP 上的標准 HTTP 進行傳輸。最終,所有消息均通過 IP 進行傳輸。
UpnP 的可應用范圍非常廣,可被應用於諸如家庭自動化、打印和圖像處理、音頻/視頻娛樂、廚房設備、汽車網絡等各種各樣的應用場合。
Digital Media Player 播放器是連接電腦、電視或音響系統的無線橋梁,它也是基於 UpnP 協議的設備。它使用標准的音頻/視頻線纜連接電視和立體聲音響系統,可通過無線網絡與電腦進行通訊,將電腦處理後的數字信息傳輸到電視和音響系統上。這樣你的數字文件就不再是只能在電腦上播放,而是可以和電視、音響系統連接,可以想象,這樣的播放效果將是 PC 電腦所無法比擬的。
為什麼選擇 Sqlite?
通常我們采用各種數據庫來實現對數據的存儲、檢索等功能,例如,Oracle,SQL Server,mysql 等等。這些產品除提供基本的查詢,刪除,添加等功能外,也提供了很多高級特性,如觸發器,存儲過程,數據備份恢復,全文檢索功能等。但實際上,很多的應用,僅僅利用到了這些數據庫產品的基本特性而已。而且在某些特殊場合的應用,這些數據庫明顯有一些臃腫。
而 Sqlite 是一個輕量級別數據庫, 具有很多不錯的特點:
Sqlite 的設計目標是嵌入式的 SQL 數據庫引擎,它是基於純 C 代碼的,已經應用到了非常廣泛的領域;
Sqlite 是直接讀寫硬盤上數據庫文件的,從而不需要額外的 server 服務端進程,即 Sqlite 是無須獨立運行的數據庫引擎;
開放源代碼, 整個代碼少於 3 萬行,有良好的注釋並且有著 90% 以上的測試覆蓋率;
少於 250KB 的內存占用(gcc);
支持視圖, 觸發器, 事務, 支持嵌套 SQL 功能;
它提供了虛擬機用於處理 sql 語句,這是一個很有趣的東西;
不需要配置,不需要安裝,也不需要管理員;
支持大部分 ANSI SQL92;
簡單易用的 API;
一個完整的數據庫就對應磁盤上面一個文件,它是一種具備了基本數據庫特性的數據文件;
同一個數據庫文件可以在不同機器上面使用, 可以在不同字節順序的機器間自由的共享;
最大支持數據庫到 2TB,而且性能僅會受限於系統可用的內存;
大部分應用比目前常見的客戶端/服務端的數據庫快,在一些簡單語句的處理性能與 mysql 和 postgreSQL 的比較,除了一些不常用的語句外,比其它兩個都快;
沒有其它依賴,可以使用在多種操作系統平台上;
以下為 Sqlite 的代碼架構圖,它由核、後端、SQL 編譯器、輔助工具組成。
你可以看出 Sqlite 非常簡單,Sqlite 的設計思想就是簡單:
1、簡單的在程序中使用它
2、簡單的管理
3、簡單的操作
4、簡單的維護和定制
Sqlite 的代碼架構圖
數據庫結構的設計
在 Media NAS 系統中涉及的媒體文件類型有三類:Video,Audio,Image。基於這三類文件,我們對數據庫做了結構設計。
VideoTable 的設計:
顯示標題(100字節),Video 時長(整數型),Video 長、寬(整數型),文件全路徑名(1024 字節),所在目錄名(260 字節);
AudioTable 的設計:
顯示標題(100 字節),Audio 時長(整數型),流派(100 字節),歌唱者(100 字節),專輯(100字節),文件全路徑名(1024 字節),所在目錄名(260 字節);
ImageTable 的設計:
顯示標題(100 字節),Image 長、寬(整數型),專輯(100 字節),文件全路徑名(1024 字節),所在目錄名(260 字節);
對應的 sqlite 操作命令為:
CREATE TABLE VideoTable (titlename VARCHAR(100), time INTEGER, videowidth INTEGER, videoheight INTEGER, filename VARCHAR(1024), dir VARCHAR(260)); CREATE TABLE AudioTable(titlename VARCHAR(100), time INTEGER, genre VARCHAR(100), artist VARCHAR(100), album VARCHAR(100), filename VARCHAR(1024), dir VARCHAR(260)); CREATE TABLE ImageTable (titlename VARCHAR(100), time INTEGER, imagewidth INTEGER, imageheight INTEGER, genre VARCHAR(100), filename VARCHAR(1024), dir VARCHAR(260));
需要說明的幾點:
1、存儲在 Sqlite 中的記錄內容,最好采用 UTF8 編碼的文本內容。這樣就不會丟失記錄信息,否則的話,有些多國語言的內容做了 Unicode 轉換後將會丟失。
2、在設計中要考慮到播放請求時,並不是一次請求全部的數據,而是請求一部分,即從某位置開始,請 求若干條記錄,並且是需要按一定的規則排序。對記錄中某項的查詢語句,如: select * from AudioTable order by titlename limit startindex, requestcount ;其中需要 加上查詢時啟始位置與需要查詢的個數。還要包括以 titlename 作為排序的依據。
3、在需要一次得到某種媒體類型的記錄的全部條數的地方,需要進行優化,可以使用類似下面的語句:
select count(*) from AudioTable;
它會直接返回全部的 audio 類型的記錄的總條數。這樣查詢的速度,和對系統資源的占用率會有較大改善。
4、在對 audio 的流派,專輯,歌唱者進行查詢時,需要使用類似如下的命令:
select artist from AudioTabel group by artist order by artist; 這樣得到的記錄內容就是經過排序了的 artist 類型。
5、數據的動態改變
在應用中,將涉及到需要在系統運行期間動態掃描新添加的媒體,這個時候就需要將已有的數據庫文件拷貝一份,並將新添加的媒體文件使用拷貝後新的數據庫做為掃描時使用的數據庫文件。掃描完成後,再將舊的數據庫文件用新的文件替換,從而保證在系統運行期間,舊的數據依然是能被訪問到的。在這個過程中,需要對數據庫進行同步,使用 sem_t 即可,涉及到的操作函數包括 sem_init,sem_destroy,sem_wait,sem_post。在需要對數據庫進行替換前,使用 sem_wait,替換後使用 sem_post 進行釋放。從而可以防止多個線程對數據庫的操作所引起的錯誤。
Sqlite 與應用的結合
Sqlite 的特點決定了它與應用結合時將會是非常便捷的。作為數據的存儲介質,Sqlite 文件將被保存成一個普通的文本文件,它無須一個 server 進程來提供服務,對 Sqlite 數據文件的直接操作即可以完成我們想要的工作。
在應用層,編寫了一個對 Sqlite 操作的簡單的封裝。而且在這個過程中,可以體會到對 Sqlite 的操作是如此的便捷。
如:
DBInitial; 定義 Sqlite 操作時的回調函數 DBRelease; 釋放 Sqlite 數據文件 DBOpen; 調用 sqlite_open 打開數據庫文件 DBClose; 調用 sqlite_close 來關閉數據庫 DBExecute; 執行 SQL 命令 DBRecordsetInit; 執行 select,得到記錄集 DBRecordsetRelease; 調用 sqlite_free_table 來釋放結果集 DBGetCharacterField 得到記錄集中的一個域
在應用層,使用上面的包裝,即可以完成對 Sqlite 數據庫的操作,使用簡潔,執行效率高。
總結
在整個系統開發過程中,感覺到用 Sqlite 數據庫來開發,系統性能高,充分地體現了展示了輕量型數據庫在開發應用中的便捷。
你在自己的項目中使用哪種類型的數據庫呢,不防也將這個小巧的數據庫應用到自己的項目中,你會體會到它給你帶來的巨大優勢。
關於作者
余濤,高級軟件工程師,現從事 linux 嵌入式系統的開發工作,主要研究方向嵌入系統,UPNP 多媒體播放系統。您可以通過電子郵件 [email protected] 和他聯系。希望能與更多的朋友交流關於 Linux 方面的知識。