用 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 电脑所无法比拟的。
#p#副标题#e#
为什么选择 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 的代码架构图
#p#副标题#e#
数据库结构的设计
在 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 进行释放。从而可以防止多个线程对数据库的操作所引起的错误。
#p#副标题#e#
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 多媒体播放系统。您可以通过电子邮件 yut616@21cn.com 和他联系。希望能与更多的朋友交流关于 Linux 方面的知识。 |