DSS 源码阅读指南[0]

最近在读Darwin Streaming Server源代码,刚刚开始,随意记录一些信息。

DSS 代码非常旧,MacOS forge上的版本还停留在6.0.3,看样子应该是2003年的陈年老酒,不过即便如此还是有许多值得学习的地方。

说到阅读源码,是让人感到压力山大浑身不自在的事情,无论是别人写的,还是自己写的。好在DSS的Documentation目录下有许多非常值得阅读的资料,可供参考。读完 AboutTheSource.html , DevNotes.html, FAQ.html 和 QTSSAPIDocs.pdf 之后,感觉DSS的代码框架已经一目了然,并且有迫不及待去看相关代码实现的冲动了。

DSS的RTP实现建立在所谓“reliable UDP”之上,何谓“可靠UDP”,让人非常疑惑,在Documentation中找到Reliable RTP Whitepaper,可窥端倪。网上也有介绍苹果自家的“reliable UDP”的设计、实现的相关介绍,可以参考。

这些文档从系统设计的角度介绍了DSS的全貌。系统设计一直是我很感兴趣的一个话题,DSS的系统设计理念很值得学习和思考。模块化、异步执行(不阻塞)、消息队列与派发,这些也都是现代服务器/操作系统的设计理念。

这是阅读学习DSS代码的一篇小小指引,后续会逐渐增加一些自己的发现。

新的革命:自由网络 vs. 安全网络

我起了一个巨大的标题。我本不该的。我希望用这样的标题党引起更多人注意这个问题,共同来解决这个世界性的世纪难题。

这篇bo的内容起始于我关于网络实名制的一些想法。但是不成熟,所以没有抛出来。很快就遇到的CSDN以及其他诸多著名网站密码流出事件,更是证明了网络安全问题其实是长久以来悬而未决的难题。后来美国又发起了SOAP的论战,当时俺兴趣不在这个上,也没有仔细去读新闻。过年回来后知后觉地追踪了下时下火热的方韩大战的新闻旧闻,说来这故事跟网络自由和安全其实有些相关性,那就是拷问网络言论究竟应不应该受到责任约束的问题。今天上午在公司无事,反过头来详细阅读了译言翻译的上许多对SOAP和PIPA的详细分析和报道。再反思以前一直思考着的,互联网未来发展的趋势;该不该实名制;用什么方式帮助大家公平地排队买火车票;怎样有效地分发和贩售知识,这种新世纪的财富;怎样有效地让人们在互联网上能够公平自由地发表言论,同时又能切实地为自己的言论负责;怎样保证信息流动性的同时还保证他的可靠性。因为一直思考着这些,发现这些问题其实源于同宗,于是就有了今天这个标题。

经过半个世纪的发展,互联网正走向新世纪,新革命。互联网极大便利人们的同时,也极大地改变,甚至可以说是,毁灭着人类。因为他的便利性地下藏着的是巨大的漏洞,无尽的陷阱。互联网最初的设计来自于学校,而目的是用于军事。也就是说,最早的互联网使用者,是科研机构和政府部门,是用于组织内部,是互相信任的不同机构的通讯网。互联网,从其设计之初的基础来看,就是一个信任网络。互联网是一个明码通信网络。当然,VPN,SSL等技术从不同层次改进了网络的安全性,但VPN并不是互联网的一部分,只是一个局域安全网,而SSL则会遇到密钥分发这个密码学永远要面对的难题,中间人攻击仍然是他的软肋。目前网络常用的用户名-密码验证机制,有着他的巨大漏洞。这绝不是说网站增强自己数据库的安全性就能解决的问题。举例而言,假如我是黑客,我完全可以建立一个用明码存储用户名密码的网站,然后用吸引眼球的东西引诱大家来注册。例如说糟糕图床,例如说二次元漫画,例如说盗版游戏下载,例如说灵异事件讨论和照片分享,等等。你会说我不沾游戏不看盗版电影不上糟糕站,那你会不会订打折机票,会不会团购旅游?恭喜你,你又中招了。黑客世界除了能逆向工程软件和系统,还有逆向社会工程学。你会说我每个网站都用不同的用户名不同的密码。但是这个世界有几个你这样的聪明人,十几亿网民中有千分之一的密码泄漏,就够养活一个师的黑客大军了。

强调绝对的网络自由的后果就是,网络不存在任何安全性可言。那就会陷入无政府主义的痛苦深渊。每个上网的人都必须是黑客,否则就是黑客押镖保护下的惊慌旅客,再不然就是待宰羔羊。网站安全要靠站长自身素质、纪律和技术支持;上网安全要靠网民自身武艺高超。那将会是一个骗子横行的世界。例如我可以开发一个720软件,密码存我这,包你上网无忧。结果实际我是地下黑客组织的大后台,我一边大肆兜售安全软件,一边就把所有人的私人信息插标出售。那你还敢信银行专用防火墙吗?那你还敢信全自动保安系统吗?那你还敢信网上银行吗?自动操盘bot?天哪没有网络安全的世界是不可想象的。

那么,反其道而行之呢?建立强有效的安全网络?问题是如何去做,问题是技术水平是否足够,问题是国际政治环境是否允许,问题是新的政策新的法律新的技术将如何影响现有的利益集团。

实名制:毫无疑问,实名制会给网络减少不少乐趣。用一个名字拉风的马甲胡吹海泡的时代一去不复返了。但是好处呢?每个人都要为自己说的话负责;或者仍然允许匿名,但是如果你用的是匿名,则你说的话根本没人搭理。谩骂、水军、造谣、煽动、这些毫无营养的网络垃圾终于可以省省了。更多的空间让给建设性的建议和评审,让给知识的有效流动。同时,实名制的信息签名制度使得一个人说的话在被复制和传播的时候他的签名被同时传播,于是制止了匿名转载,保证了CC实现。另外如果有一个强有力的独立部门承担网络ID的认证工作,则任何其他网站都不需要保存用户的密码了,于是再也没有密码泄漏问题。当然前提是那个独立认证部门必须切切实实的强有力,值得信赖。
技术难度:签名的不可复制性需要密码学的严谨论证;公民的网络ID将成为他的新一代身份证,同时也是他全部虚拟财产的钥匙,需要强有力的安全部门保证这个帐号的安全。

默认加密:现代互联网仍然是默认明文的。使用一些简易设施,任何人都能截取局域网或者wifi中传递的私人信息。加密应该在网络的底层实现,而不是依赖应用程序提供者的道德约束。问题是想要从底层修改网络协议,影响面太广,不是一日可完成的任务。并且这要求世界各国的网站齐心合力一同做到。新的IPV6协议中包含更多的安全部件,但仍然是可选项。强制安全的网络协议是未来人类的必然选择。
技术难度:向后兼容

异构云系统:这是我的独立发明。未来互联网就是云系统。但是现在的云系统都是同构的,同一个系统内部的无数并行运算组件其实是运行在同一个机房几乎完全相同硬件上的完全相同的软件。这也就是说,无论你的安全机制多么严密,只要黑客攻克了你那么一点点,那么所有的机器,所有的组件,全都被攻克了。我认为真正安全的系统必须是异构复合的。同样是处理邮件,同一个服务,在云端由不同的并行组件,就可能由成千上万种完全不同的方式处理掉(当然结果是相同的,异曲同工嘛)。这在自然界,就是称作“物种多样性”的杰作。这样黑客就算创造出一种病毒,也仅仅能摧毁某种特定类型的细胞,而其他的细胞完全不受影响。那种特定类型的细胞灭绝之后,这种病毒也就跟着一起灭绝了。要如何实现异构复合的云计算系统?毫无疑问要依赖遗传编程。啊伟大的人工智能,创造奇迹吧,改变软件工程的历史性大手笔!
技术难度:遗传编程的工程应用。于此相比,更大的难度在于安全性对于服务提供商而言是附加题,他们不会在没有利益驱动的前提下自动花大笔的精力去做。因此此事的推动需要等待互联网的进一步进步。

我写了好多,但还是太少了。但是很明显的,再多写也没有意义。推动网络革命需要的技术进步,远远比不上他所需要的社会进步那么急切。如果互联网不能进一步前进,进一步暴露他的问题,给各利益方以驱动,则即使技术摆在那里,也没有人想要去用。结果又变成了,技术拯救人类和技术毁灭人类的死亡竞速。

因此纸尽言犹,先就此收笔,静候网络发展的佳音吧。

系统的民主和独裁

关于系统设计,我想到了两件事情

从性能的角度考虑,系统设计应该尽可能隔离物理设备,向用户提供透明的接口。最好让所有的东西都是普通的变量。例如,为什么要区分内存上的结构体和磁盘里的文件呢?完全可以让用户认为,定义一个变量,他就在内存里,又随时可以固化到磁盘上。至于这个变量,实际上放在哪里,由操作系统决定。例如一个很复杂的结构体数组,就可以开辟在磁盘上,并作内存上的缓冲。当然这种做法其实跟现在系统的内存分页调度方式最终结果是类似的。但是如果一开始选择权就在系统的话,自由度更大。

从这个角度考虑下去,很容易想到的就是文件的结构化管理。为什么二进制文件比纯文本文件更难读懂?因为二进制文件没有统一的管理模式。同样是二进制的,c语言里调试结构体的时候就完全不会觉得费力,为什么呢?因为头文件里声明了结构体的各成员类型。如果能把结构体的声明嵌套在二进制文件里,使其成为自解释的,则二进制文件能够充分发挥其存取方便、节约空间的好处,同时防止其调试困难人类难以理解的缺点。既然文件头的规范已成定则,完全可以考虑把文件的结构声明放在文件尾。当然需要订立标准。假如让我来设计草案的话,可以如下所述:

(1) 为了兼容现有文件结构,自解释信息放在文件末尾,紧接在原始文件的后面。使用特殊的头部以区分其他文件。

(2) 文件结构为树状结构,从根部开始,使用“描述块”来描述每个节点的数据结构定义,直至叶子节点。

(3) 叶子节点使用字节数表示其单位大小

(4) 父节点可以是数组*、结构体

这里有一个需要讨论的问题,就是当父节点是数组的时候,如何确定数组的长度。通常有两种做法决定数组的长度,一者是使用特殊标记的结束符号,二者是使用一个数组长度的数值来确定。当数组长度非常长的时候,可能32位int无法表示,可以总是使用64位int又会浪费空间,假如未来出现超级巨大存储器,甚至可能64位int都不够表示,还需要更加巨大的数字。所以我认为使用结束符号表示数组结尾是更好的方法。当然由于这里只是YY,可以随便想。例如也可以使用一个配置选项来决定使用哪种方式表示。

另外结构体的表示,当其成员用到其他已定义的成员时,也可以使用序号表示那个成员的结构声明。

使用这样的一种方法,程序员想要操作文件系统时将会非常轻松,例如配置文件,可以认为是使用换行符隔开的一系列字符数组。每一个换行符隔开的行单元可以单独地被交换到内存,或者写回文件。由于在文件定义的时候就确定了文件是以行为单位独立的,操作系统在这个层次可以做大量优化。例如并行程序读写不同行时文件无需加锁,而是将这两个被读写的行交换到内存中进行操作。例如编译文件,在某一行插入时,不必对文件的后面部分依次推后重新写回,而可以只在那一个行上做内存缓冲和读写,当系统空闲或卸载磁盘前再做写磁盘操作(大大提高并行性并减少磁盘写数量)。对于大文件,系统可以自动对行进行索引,从而提高随机读写行的性能,等等等等。

另外能够方便程序员的是,这样的文件由于已经附加了结构说明,只需复制这个文件,无需附加其他说明,就可在其他的程序员那里方便地阅读和使用。例如一个游戏的资源包文件,其实是一个复杂的树状结构。如果附加定义清晰的结构说明,其他程序员即使没有源代码也可以轻松地理解其内容。当然如果为了保密,可在发布时去掉文件说明。由于仅是附加在文件尾的部分,去掉也不会对文件本身造成任何影响。

在这个角度YY得太多了。总之这样的思路就是,操作系统完全是独裁的,程序员只能提请求,但这个请求究竟以什么样的方式实现,有操作系统来决定。好处是,系统所处的地位比应用程序高很多。系统知道现在全局资源的情况。总的内存占用、磁盘访问频率、网络流量(甚至可以考虑将部分数据上传到云端作为一种持久化措施,程序员请求固化一段内容,甚至可以不知道是固化在本地了还是在云端了),等等,这些东西作为一个应用程序是没办法想太多的,想太多容易“过早优化”,可是完全不想最后查性能瓶颈又是各种麻烦。如果系统能够智慧地处理各种情况,根据当前系统状态动态选择最合适的策略,则系统性能可以做到最优化,硬件使用率可以达到最高。

但这只是从系统的角度考虑。

假如从应用程序的角度考虑呢?假如我是应用程序的开发者,我绝对不喜欢操作系统额外做很多事。我希望我做的事情没有副作用,可确定。这也能方便我调试,方便我bug复现。例如,假如真的系统可能把数据固化到云端,假如网络通讯部分驱动有bug,可能我请求一个变量,十次有三次不成功,七次成功。因为恰好那三次定义到云端了,而后来的七次定义在本地。如果是这样,一旦程序复杂,bug丛生,程序员会气急败坏。相信程序员,把一切都交给程序员,这就是Unix的系统逻辑。一个绝对民主的系统。

可是,当权利交给程序员的时候,程序员就成为独裁者了。好的代码自然能够绝对有效地利用系统提供的资源,但坏的代码不仅自身运行不好,还会占用其他程序的资源和空间,让其他程序都变得缓慢甚至无法运行。让应用程序在他可见的那个狭窄范围内,做系统级的性能优化决策,又实在太为难应用程序员了吧。相比无数应用程序群氓的独裁,莫不如系统一个人的独裁可靠一些。因为只需把一个系统做好,就可以让所有的应用程序有好的表现。或许这个思路更好?

论资源抢占的系统设计

怎么会想到这个问题,出发点是来自提出一个更通用的多线程架构的问题。其实这个问题我现在讨论有点过早,因为至今还没仔细研究过go和erlang,不了解多线程编程的现状。但总归在这个blog的小小圈子里,随便抒发几句应该是问题不大。

其实我的想法是很简单的,就是想增加一个 “任务” 的概念。这个必然很多语言很多系统已经提供了,我为什么还要提。我主要是感觉,现在的多线程编程,还有网络编程,每个程序都自己定义一套多线程管理、进程池、线程池、网络连接池、数据库连接池等等概念。虽然有库函数,不必每次从头造轮子,但每个程序一份几乎完全雷同的管理机制,绝对是有问题的。

况且,现在的操作系统,除了CPU占用这一点实现了“抢占”之外,其他的系统资源仍然是依赖程序间的谦让协作的。我前几天发的帖子,就是因为adb的一个bug,导致占用了过多的系统连接,导致其他程序无法使用网络。同样的例子,臭名昭著的迅雷,因为过量占用连接数导致你根本无法上网。虽然最近迅雷提供了种种功能,他会检测你有没有使用浏览器,他会检测某些著名的端口(对应各大著名网游),确定你是不是在打游戏,等等,来谦让地给你腾出一些网络带宽。但问题是,这样看来,是不是太委屈迅雷大哥了。虽然霸占过多网络资源是他的不对,但是研究到底应该使用多少资源,并不是一个应用程序能够做到的事情(迅雷也只是经验性的猜测,你自己写的网游、小众的网络服务,他一定是无法猜测到的)。

参考CPU抢占的系统设计,其实资源抢占完全也是可以做到的。还可以参考虚拟内存的方式,给每个应用程序足够巨大的虚拟资源空间,并使用工作集、缺页调度等机制,调度所有的资源。这样擅自开辟了大量网络连接的服务(如adb),也不会导致系统无法打开更多的网络连接,霸占了大量资源的迅雷,也无法阻止其他程序连接网络(因为有工作集的限制)。操作系统可以根据资源使用的活跃程度等因素调度资源,例如当其他程序都不使用网络时,就可以让例如迅雷这样开辟了过多连接的程序拥有更大的工作集,保证系统资源的最大化利用。

好吧,话说到这里已经扯开去了。前面提到的多线程管理的机制,其实跟这个资源抢占的机制没有任何关系。只是因为思路飘忽扯到这里来了。说回那个多线程管理的问题,也是一样的,我希望提供一种机制说明任务的并发逻辑(可能要使用新的语言,至少C语言无法表达并发逻辑这种概念),然后要使用什么样的并发度,这个决定让系统来做。因为系统有多少内存资源,有多少CPU资源,这些事情本不该是应用程序该知道、该负责的事情。尤其是,跟本身的应用程序一起,系统里还有哪些其他的程序在跑,他们对内存和CPU的消耗如何,更加不是应用程序的职责范围能知道的。但是决定一个任务的并发度,必须从系统级思考问题。因此把并发逻辑列清楚之后,让系统去决策如何并发,才是最良好的策略。我不知道go语言或者erlang这些传说有着高度并发支持的语言是否已经做到这样,如果是这样的话,我就再次后知后觉了;不过作为一个思考练习,也是挺好的~(热烈欢迎评论拍砖=)

好吧,把资源抢占和这个多线程管理机制综合到一起,就变成了更系统更完善的系统管理机制。因为并发度不仅要考虑内存CPU,也要考虑硬盘、网络、设备等等等等。把所有的资源使用频率整合统筹调度,就能得到最优化的系统,当然这个多维度的最优问题,也将成为一个巨大的算法难点。也正是因为想到这里,我才感到格外兴奋。

说实话,即使用十年时间去开发出来这样一个系统也不会太迟。但要做到一点,就是对市场现有产品的兼容性。如果能运行java虚拟机,或者能兼容linux系统调用(也就是说新系统在linux的基础上修改得到,说实话我觉得这是一个靠谱的打算),或者至少旧有的程序代码通过编译能够运行在新的系统上,并且仍能体现系统的优越性,那么新东西做出来就不会没有市场没有价值。

不过我真的要跳这么个大坑么。。还是仅仅满足于YY然后坐看系统更替风云变幻?说实话,自己感觉暂时能力有限不足以完成伟任呢,或者说过于浮躁也有可能。暂时先记录一下吧,也许明天就会自否命题了呢囧|||

有时间先去研究下go和erlang哈哈:)

PS. 还有一个关于通用缓冲区设计的思考练习,目前正在开发和实验中,有结果了一定写bo!