北京南站附近景点,群晖wordpress二级目录,肇庆做网站的有,移动端网站优秀案例注#xff1a;本文为 “左耳听风”陈皓的 unix 相关文章合辑。
皓侠已走远#xff0c;文章有点“年头”#xff0c;但值得一阅。
文中部分超链已沉寂。 Unix 传奇 (上篇)
2010 年 04 月 09 日 陈皓
了解过去#xff0c;我们才能知其然#xff0c;更知所以然。总结过去…注本文为 “左耳听风”陈皓的 unix 相关文章合辑。
皓侠已走远文章有点“年头”但值得一阅。
文中部分超链已沉寂。 Unix 传奇 (上篇)
2010 年 04 月 09 日 陈皓
了解过去我们才能知其然更知所以然。总结过去我们才会知道我们明天该如何去规划该如何去走。在时间的滚轮中许许多的东西就像流星一样一闪而逝而有些东西却能经受着时间的考验散发着经久的魅力让人津津乐道流传至今。要知道明天怎么去选择怎么去做不是盲目地跟从今天各种各样琳琅满目前沿技术而应该是去 —— 认认真真地了解和回顾历史。
Unix 是目前还在存活的操作系统的元老了走过了 40 年的历程。在技术更新如此迅速的计算机世界的今天Unix 始终保持它那神圣的光环它那曲折和令人叹息的历史以及由它引发的思想变革对当今计算机文化造成的深远影响这 40 年所产生的人和事让它成为了一个传奇不能不让人为之惊叹。
这是一段所有从事计算机行业人员尤其是软件开发人员需要了解的历史。Unix 的传奇历史是整个计算机世界文化最具代表性的它对整个计算机世界文化的影响也是最巨大最深远的。他给人带来的不单单的对过去的回味更为我们带来了计算机世界的新思潮。
了解这段的历史的人才能体会计算机世界变迁过程中的是是非非才能了解计算机世界中的文化从而才能参与到整个计算机革命的大潮中。希望这段历史这篇文章能让你感受到计算机世界那强力的脉搏从而让你踏上这条令人充满激情的道路。
上篇 目录
Unix 起源Unix 分裂Unix 的法律纠纷GNU 开源组织Linux 横空出世Linux 今天的领袖
Unix 起源
回顾 Unix 历史我们就要说一下一个叫 MULTICSMultiplexed Information and Computing Service的项目。上世纪六十年代时大部份计算机都是采用批处理Batch Processing的方式也就是说当作业积累一定数量的时候计算机才会进行处理。那时我们熟知的美国电话及电报公司American Telephone and Telegraph Inc.ATT、通用电器公司General ElectricsG.E.及麻省理工学院Massachusetts Institute of TechnologyMIT计划合作开发一个多用途General-Purpose、分时Time-Sharing及多用户Multi-User的操作系统也就是这个 MULTICS其被设计运行在 GE-645 大型主机上。不过这个项目由于太过复杂整个目标过于庞大糅合了太多的特性进展太慢几年下来都没有任何成果而且性能都很低。于是到了 1969 年 2 月贝尔实验室Bell Labs决定退出这个项目。
熟悉这段历史的人都知道贝尔实验室中的有个叫 Ken Thompson 的人他为 MULTICS 这个操作系统写游戏了个叫 “Space Travel” 的游戏在 MULTICS 上经过实际运行后他发现游戏速度很慢而且耗费昂贵 —— 每次运行会花费 75 美元。退出这个项目以后。他为了让这个游戏能玩所以他找来 Dennis Ritchie 为这个游戏开发一个极其简单的操作系统。这就是后来的 Unix。值得一提的是当时他们本想在 DEC-10 上写后来没有申请到只好在实验室的墙角边找了一台被人遗弃的 Digital PDP-7 的迷你计算机进行他们的计划这台计算机上连个操作系统都没有于是他们用汇编语言仅一个月的时间就开发了一个操作系统的原型他们的同事 Brian Kernighan 非常不喜欢这个系统嘲笑 Ken Thompson 说“你写的系统好真差劲干脆叫 Unics 算了。”Unics 的名字就是相对于 MULTICS 的一种戏称后业改成了 Unix。于是Unix 就在这样被游戏和玩笑创造了当时是 1969 年 8 月。也就是这一年Linux 之父 Linus Torvalds 在芬兰出生了。
1971 年Ken Thompson 写了充分长篇的申请报告申请到了一台 PDP-11/24 的机器。于是 Unix 第一版出来了。在一台 PDP-11/24 的机器上完成。这台电脑只有 24KB 的物理内存和 500K 磁盘空间。Unix 占用了 12KB 的内存剩下的一半内存可以支持两用户进行 Space Travel 的游戏。而著名的 fork () 系统调用也就是在这时出现的。
到了 1973 年的时候Ken Thompson 与 Dennis Ritchie 感到用汇编语言做移植太过于头痛他们想用高级语言来完成第三版对于当时完全以汇编语言来开发程序的年代他们的想法算是相当的疯狂。一开始他们想尝试用 Fortran可是失败了。后来他们用一个叫 BCPLBasic Combined Programming Language的语言开发他们整合了 BCPL 形成 B 语言后来 Dennis Ritchie 觉得 B 语言还是不能满足要求就是就改良了 B 语言这就是今天的大名鼎鼎的 C 语言。于是Ken Thompson 与 Dennis Ritchie 成功地用 C 语言重写了 Unix 的第三版内核。至此Unix 这个操作系统修改、移植相当便利为 Unix 日后的普及打下了坚实的基础。而 Unix 和 C 完美地结合成为一个统一体C 与 Unix 很快成为世界的主导。
Unix 的第一篇文章 “The UNIX Time Sharing System” 由 Ken Thompson 和 Dennis
Ritchie 于 1974 年 7 月的 the Communications of the ACM 发表。这是 UNIX 与外界的首次接触。结果引起了学术界的广泛兴趣并对其源码索取所以Unix 第五版就以 “仅用于教育目的” 的协议提供给各大学作为教学之用成为当时操作系统课程中的范例教材。各大学公司开始通过 Unix 源码对 Unix 进行了各种各样的改进和扩展。于是Unix 开始广泛流行。
Unix 分裂
1978 年对 Unix 而言是革命性的一年因为学术界的老大柏克利大学 UC Berkeley推出了一份以第六版为基础加上一些改进和新功能而成的 Unix。这就是著名的 “1 BSD1st Berkeley Software Distribution”开创了 Unix 的另一个分支BSD 系列。 同时期ATT 成立 USGUnix Support Group将 Unix 变成商业化的产品。从此BSD 的 Unix 便和 ATT 的 Unix 分庭抗礼Unix 就分为 System IV 和 4.x BSD 这两大主流各自蓬勃发展。
1979 年发布的 Unix 第七版被称为是 “最后一个真正的 Unix”这个版本的 Unix 内核只有 40K bytes。后来这个版本被移植到 VAX 机上我在大学时学习 C 语言时用过这个 VAX 机我还记得那时上 VAX 机最大的爱好就是使用 talk 命令和别人聊天呵呵。20 世纪 80 年代相继发布的 8、9、10 版本只授权给了少数大学。
1982 年ATT 基于版本 7 开发了 UNIX System Ⅲ 的第一个版本这是一个商业版本仅供出售。为了解决混乱的 UNIX 版本情况ATT 综合了其他大学和公司开发的各种 UNIX开发了 UNIX System V Release 1。这个新的 UNIX 商业发布版本不再包含源代码所以加州大学 Berkeley 分校继续开发 BSD UNIX作为 UNIX System III 和 V 的替代选择。BSD 对 UNIX 最重要的贡献之一是 TCP/IP。BSD 有 8 个主要的发行版中包含了 TCP/IP4.1c、4.2、4.3、4.3-Tahoe、4.3-Reno、Net2、4.4 以及 4.4-lite。这些发布版中的 TCP/IP 代码几乎是现在所有系统中 TCP/IP 实现的前辈包括 ATT System V UNIX 和 Microsoft Windows 中的 TCP/IP 都参照了 BSD 的源码。
同时其他一些公司也开始为其自己的小型机或工作站提供商业版本的 UNIX 系统有些选择 System V 作为基础版本有些则选择了 BSD。BSD 的一名主要开发者Bill Joy在 BSD 基础上开发了 SunOS并最终创办了 Sun Microsystems。
1991 年一群 BSD 开发者Donn Seeley、Mike Karels、Bill Jolitz 和 Trent Hein离开了加州大学创办了 Berkeley Software Design, Inc (BSDI)。BSDI 是第一家在便宜常见的 Intel 平台上提供全功能商业 BSD UNIX 的厂商。后来 Bill Jolitz 离开了 BSDI开始了 386BSD 的工作。386BSD 被认为是 FreeBSD、OpenBSD 和 NetBSD、DragonFlyBSD 的先辈。
这是一个 ATT 妄图私有化的 Unix 的时代。为了私有化 Unix1986 年 IEEE 指定了一个委员会制定了一个一个开放作业系统的标准称为 POSIX (Portable Operating Systems Interface)。最后加上个 X不知道是为了好听还是因为这本质上是 UNIX 的标准。当然ATT 的 Unix 取得了这个标准制订战争的胜利还取得了 Unix 这个注册商标。此时 BSD 的拥护者自喻为冷酷无情的公司帝国的反抗军。就销售量来说ATT UNIX 始终赶不上 BSD/Sun。到 1990 年ATT 与 BSD 版本已难明显区分因为彼此都有采用对方的新发明。
这段时期从实验室出来的被全世界所分享的 Unix正处于被私有化的关键时期。这里有一个笑话 ——《Alice 梦游 UNIX 仙境》见下文
Unix 的法律纠纷
Berkeley Software Design, IncBSDI很快就与 ATT 的 UNIX Systems LaboratoriesUSL附属公司产生了法律纠纷USL 是 ATT 注册的公司。ATT 为了拥有 System V 版权以及 Unix 商标为了垄断 Unix1992 年USL 正式对 BSDI 提起诉讼说 BSD 剽窃他的源码。而最终了结了好评如潮的 BSD 系统。
由于最后判决悬而未决这桩法律诉讼将 BSD 后裔的开发特别是自由软件延迟了两年这导致没有法律问题的 Linux 内核获得了极大的支持。Linux 跟 386BSD 的开发几乎同时起步Linus 说当时如果有自由的基于 386 的 Unix-like 操作系统他就可能不会创造 Linux。尽管无法预料这给以后的软件业究竟造成了什么样的影响如果没有这个法律纠纷很有可能没有今天的革命性的 Linux但有一点可以肯定Linux 更加丰富了这块土壤。
这场官司一直打到 ATT 将自己的 Unix 系统实验室卖掉新接手的 Novell 公司采取了一种比较开明的做法允许 BSDI 自由发布自己的 BSD但是前提是必须将来自于 ATT 的代码完全删除于是诞生了 4.4 BSD Lite 版由于这个版本不存在法律问题4.4BSD Lite 成为了现代 BSD 系统的基础版本。
这桩诉讼最终在 1994 年 1 月了结更多地满足了 BSDI 的利益。伯克利套件的 18,000 个文件中只有 3 个文件要求删除另有 70 个文件要求修改并显示 USL 的版权说明。这项调解另外要求USL 不得对 4.4BSD 提起诉讼不管是用户还是 BSDI 代码的分发者。于是BSD Unix 走上了复兴的道路。BSD 的开发也走向了几个不同的方向并最终导致了 FreeBSD、OpenBSD 和 NetBSD 的出现。
从 ATT 意识到了 Unix 的商业价值不再将 Unix 源码授权给学术机构以来到以后的几十年Unix 仍在不断变化其版权所有者不断变更授权者的数量也在增加。Unix 的版权曾经为 ATT 所有之后 Novell 拥有了 Unix再之后 Novell 又将版权出售给了 SCO这一事实双方尚存在争议。有很多大公司在取得了 Unix 的授权之后开发了自己的 Unix 产品。几年前据传闻微软为了限制 Linux微软让 SCO 到法院告 Linux 剽窃其源码
由于 Unix 是由 C 语言写的所以修改和移植都很容易因此很多商业公司及学术机构均加入这个操作系统的研发各个不同版本的 Unix 也开始蓬勃发展。这才产生了今天这么多的各式各样的 Unix 衍生产品。如 AIX、Solaris、HP-UX、IRIX、OSF、Ultrix 等等。这些商业化的 Unix 基本上都是源于 ATT 授权的 Unix System V
Unix 开源组织
ATT 的这种商业态度让当时许许多的 Unix 的爱好者和软件开发者们感到相当的痛心和忧虑他们认为商业化的种种限制并不利于产生的发展相反还能导制产品出现诸多的问题。随着商业化 Unix 的版本的种种限制和诸多问题引起了大众的不满和反对。于是大家开始有组织地结成 “反叛联盟” 以此对抗欺行罢市的 ATT 等商业化行为。
另一方面关于 “大教堂”集权、封闭、受控、保密和 “集市”分权、公开、精细的同僚复审两种开发模式的对比成为了新思潮的中心思想。这个新思潮对 IT 业产生了非常深远影响。为整个计算机世界带来了革命性的价值观。
此时一个名叫 Richard Stallman 的领袖出现了他认为 Unix 是一个相当好的操作系统如果大家都能够将自己所学贡献出来那么这个系统将会更加的优异他倡导的 Open Source 的概念就是针对 Unix 这一事实反对实验室里的产品商业化私有化。尽管 Stallman 既不是、也从来没有成为一个 Unix 程序员但在后 1980 的大环境下实现一个仿 Unix 操作系统成了他追求的明确战略目标。Richard Stallman 早期的捐助者大都是新踏入 Unix 土地的老牌 ARPANET 黑客他们对代码共享的使命感甚至比那些有更多 Unix 背景的人强烈。
为了这个理想Richard Stallman 于 1984 年创业了 GNU计划开发一套与 Unix 相互兼容的的软件。1985 年 Richard Stallman 又创立了自由软件基金会Free Software Foundation来为 GNU 计划提供技术、法律以及财政支持。尽管 GNU 计划大部分时候是由个人自愿无偿贡献但 FSF 有时还是会聘请程序员帮助编写。当 GNU 计划开始逐渐获得成功时一些商业公司开始介入开发和技术支持。当中最著名的就是之后被 Red Hat 兼并的 Cygnus Solutions。
GNU 组织的建立延续了当年 Unix 刚出现时的情形并为这种情形建立了可靠的法律和财务保障。GNU 工程十几年以来已经成为一个对软件开发主要的影响力量 创造了无数的重要的工具。例如强健的编译器有力的文本编辑器甚至一个全功能的操作系统。从那时开始许多程序员聚集起来开始开发一个自由的、高质量、易理解的软件让这使得 Unix 社区生机勃勃一派繁荣景象。
自 90 年代发起这个计划以来GNU 开始大量的产生或收集各种系统所必备的组件像是 —— 函数库libraries、编译器compilers、调式工具debugs、文本编辑器text editors、网站服务器web server以及一个 Unix 的使用者接口Unix shell等等等等。但由于种种原因GNU 一直没有开发操作系统的 kernel。正当 Richard Stallman 在为操作系统内核伤脑筋的时候Linux 出现了。
Linux 横空出世
1990 年Linus Torvalds 还是芬兰赫尔辛基大学的一名学生最初是用汇编语言写了一个在 80386 保护模式下处理多任务切换的程序后来从 MinixAndy Tanenbaum 教授所写的很小 的 Unix 操作系统主要用于操作系统教学得到灵感进一步产生了自认为狂妄的想法 —— 写一个比 Minix 更好的 Minix于是开始写了一些硬件的设备驱动程序一个小的文件系统。这样 0.0.1 版本的 Linux 就出来了但是它只具有操作系统内核的勉强的雏形甚至不能运行你必须在有 Minix 的机器上编译以后才能玩。这时候 Linus 已经完全着迷而不想停止决定踢开 Minix于是在 1991 年 10 月 5 号发布 Linux 0.0.2 版本在这个版本中已经可以运行 bash 和 gcc。
从一开始Linus 就决定自由扩散 Linux包括原代码随即 Linux 引起黑客们hacker的注意通过计算机网络加入了 Linux 的内核开发。Linux 倾向于成为一个黑客的系统 —— 直到今天在 Linux 社区里内核的开发被认为是真正的编程。由于一批高水平黑客的加入使 Linux 发展迅猛几乎一两个礼拜就有新版或修正版的出现到 1993 年底 94 年初Linux 1.0 终于诞生了Linux 1.0 已经是一个功能完备的操作系统而且内核写得紧凑高效可以充分发挥硬件的性能在 4M 内存的 80386 机器上也表现得非常好至今人们还在津津乐道。时至今日kernel 的版本已经出到 2.6。Linux 的发展不像传统的软件工程它完全是透过网络集合世界各地的高手而成的一套操作系统在这里我们也可以见识到网络快速传播的威力。Linux 初次让整个世界感觉到了开源力量和网络力量的如此强大。Linux 的标志和吉祥物是一只名字叫做 Tux 的 企鹅标志的由来是因为 Linus 在澳洲时曾被一只动物园里的企鹅咬了一口便选择了企鹅作为 Linux 的标志。
Linux 的历史是和 GNU 紧密联系在一起的。从 1983 年开始的 GNU 计划致力于开发一个自由并且完整的类 Unix 操作系统包括软件开发工具和各种应用程序。到 1991 年 Linux 内核发布的时候GNU 已经几乎完成了除了系统内核之外的各种必备软件的开发。在 Linus Torvalds 和其它开发人员的努力下GNU 组件可以运行于 Linux 内核之上。整个内核是基于 GNU 通用公共许可也就是 GPLGNU General Public LicenseGNU 通用公共许可证的但是 Linux 内核并不是 GNU 计划的一部分。1994 年 3 月Linux1.0 版正式发布Marc Ewing 成立了 Red Hat 软件公司成为最著名的 Linux 分销商之一。
严格来讲Linux 这个词本身只表示 Linux 内核但在实际上人们已经习惯了用 Linux 来形容整个基于 Linux 内核并且使用 GNU 工程各种工具和应用程序的操作系统 (也被称为 GNU/Linux)。基于这些组件的 Linux 软件被称为 Linux 发行版。一般来讲一个 Linux 发行套件包含大量的软件比如软件开发工具数据库Web 服务器例如 Apache)X Window桌面环境比如 GNOME 和 KDE办公套件比如 OpenOffice.org等等。
1991 至 1995 年间Linux 从概念型的 0.1 版本内核原型发展成为能够在性能和特性上均堪媲美专有 Unix 的操作系统并且在连续正常工作时间等重要统计数据上打败了这些 Unix 中的绝大部分。1995 年Linux 找到了自己的杀手级应用 —— 开源的 web 服务器 Apache。就像 LinuxApache 出众地稳定和高效。很快运行 Apache 的 Linux 机器成了全球 ISP 平台的首选。约 60% 的网站选用 Apache轻松击败了另两个主要的专有型竞争对手。今天的 LAMPLinux , Apache, MySQL, PHP已经成为了架构 Web 服务器的主要首选。
现如今的 Linux 不但可以装在几乎所有的主流服务器上当然也包括桌面的 X86 系统中。其还常常被用于嵌入式系统机顶盒、手机、交换机、游戏机、PDA、网络交换机、路由器、等等都是因为 Linux 那精彩的内核。
Linux 的出现不仅仅给世界带来了一个免费的操作系统也不仅仅是对 Unix 自由、共享的文化的延续它的出现带给了计算机世界自 Unix、GNU 以来更为成熟的思想和文化。
Linux 今天的领袖
Linux 和 GNU 关系是比较微妙的。那时自由软件基金会编写的用户软件工具包铺平了一条摆脱高成本专有软件开发工具的前进道路。意识服从经济而不是领导一些新手加入了 RMS 的革命运动高举 GPL 大旗另一些人则更认同整体意义上的 Unix 传统加入了反对 GPL 的阵营但其他大部分人置身事外一心编码。
Linus Torvalds 巧妙地跨越了 GPL 和反 GPL 的派别之争。他利用 GNU 工具包搭起了自创的 Linux 内核用 GPL 的传染性质保护它但拒绝认同 Richard Stallman 的许可协议反映的思想体系计划。Linus Torvalds 明确表示他认为自由软件一般情况下更好但他偶尔也用专有软件。即使在他自己的事业中他也拒绝成为狂热分子。这一点极大地吸引了大多数黑客他们虽然早就反感 Richard Stallman 的言辞但他们的怀疑论一直缺个有影响力或者令人信服的代言人。而 Linus Torvalds 正好充当了这一角色。
Linus Torvalds 令人愉快的实用主义及灵活而低调的行事风格促使黑客文化在 1993 至 1997 年间取得了一连串令人惊奇的胜利不仅仅在技术上的成功还让围绕 Linux 操作系统的发行、服务和支持产业有了坚实的开端。结果他的名望和影响也一飞冲天。Torvalds 成为了互联网时代的英雄到 1995 年为止他只用了四年时间就在整个黑客文化界声名显赫而 Richard Stallman 为此花了十五年而且他还远远超过了 Stallman 向外界贩卖 “自由软件” 的记录。与 Torvalds 相比Richard Stallman 的言辞渐渐显得既刺耳又无力。参看《Linus Torvalds 语录 Top 10》
今天我们也说不清楚是 GNU Linux 还是 Linux GNU。Linux 既不排斥开源也不排斥商业化Linus 认为好的软件是需要免费和商业化共同推进的。正是这种革命性的想法造就了今天的 Linux 火红的局面参看《谁写了 Linux》、《Linux 基金会的广告》、《Linux Distribution Timeline》。Linux 就像一股清泉流入了所有人的心中引发了很多的启迪和思考。 Unix 传奇 (下篇)
2010 年 04 月 09 日 陈皓
Unix 是目前还在存活的操作系统的元老了走过了 40 年的历程参看《Unix 40 年Unix 年鉴》、《Unix 40 年昨天今天和明天》。由它引发的思想变革对当今计算机文化造成的深远影响。这是一段所有从事计算机行业人员尤其是软件开发人员需要了解的历史。Unix 的传奇历史是整个计算机世界文化最具代表性的它对整个计算机世界文化的影响也是最巨大最深远的。他给人带来的不单单的对过去的回味更为我们带来了计算机世界的新思潮。
下篇 目录
Unix 与黑客文化Unix 的历史教训Unix 家族谱Unix 的特点Unix 的影响和哲学Unix 痛恨者手册
Unix 与黑客文化
黑客的文化和 Unix 的商业化存在着必然的联系。自从 Unix 出现黑客文化就与之而来。
1993 初一个悲观的观察家撰文指出已经有理由认为 Unix 的传奇故事连同他带有黑客文明将一同破产。许多人预测从那时起 Unix 将在六月内死亡。他们很清楚十年的 Unix 商业化使自由跨平台的 Unix 梦以失败告终。Unix 允诺的跨平台可移植性在一打大公司专有的 Unix 版本之间不停地斗嘴中丢失一个完美的操作系统最终沦为多种版本的一团乱麻这应该说是人类文明史上的一个重大悲剧。
在专有软件社会中只有像微软一样的 “集权制大教堂” 生产方式才能成功。那个时代的人悲观地相信技术世界的个人英雄主义时代已经结束软件工业和发展中的互联网络将逐渐地由像微软一样的巨型企业支配再也没有 “佐罗”世界是恺撒大帝的世界计算机文明将进入黑暗的帝国时代。黑客已经死了自由不付存在。
自从 Unix 出现以来第一代的 Unix 黑客似乎垂垂老矣衣食不饱 ( Berkeley 计算机科学研究组在 1994 丢失了自己基金)。这是一个抑压的时代。专有的商业 Unix 的结果证明那么沉重、那么盲目、那么不适当以致微软能够用那次等技术的 Windows 抢走他们生存的空间拿走他们的干粮。黑客世界的残余力量被逼到了世界上的角落里苟延残喘。
就在黑客文化日渐衰落之时美国新闻周刊的资深记者 Steven Levy 完成了著名的《黑客列传》一书书中着力介绍了一个人物Richard M. Stallman 的故事他是麻省理工学院MIT人工智能实验室领袖人物坚决反对实验室的研究成果商业化。他是商业软件社会中坚强的一员决不随波逐流建立了全新的黑客文化。
Richard M. Stallman他的登陆名 RMS 更为人熟知早在 1970 年代晚期就已经证明他是当时最有能力的程序员之一。Emacs 编辑器就是他众多发明中的一项。RMS 的目标是将后 1980 的松散黑客社群变成一台有组织的社会化机器以达到一个单纯的革命目标。也许他未意识到他的言行与当年卡尔・马克思号召产业无产阶级反抗工作的努力如出一辙。RMS 宣言引发的争论至今仍存于黑客文化中。他的纲要远不止于维护一个代码库已经暗含了废除软件知识产权主张的精髓。RMS 通过 “自由软件free software” 让黑客文化更加有自我意识。当然这个充满魅力又具争议的人物本身已经成为了一个黑客文化英雄。
只有痴迷的 “黑客” 和具有创造力的怪人结成的反叛联盟才能把我们从愚蠢中拯救出来 —— 他们接着教导我们真正的专业和奉献精神正是我们在屈服于世俗观念的 “合理商业做法” 之前的所作所为。**——《The Art of Unix Programming》
RMS 让世界上所有的人都知道入侵电脑系统只是低级不入流的黑客干的事真正的黑客是为了自由为了软件的自由为了挑战计算机世界中的霸权主义而斗争。他们不是街头小混混他们更像是绿林好汉更像是罗宾汉更像是佐罗。就像渴望民主的人民同专制的政府斗争一样。RMS 领导着许多的黑客通过互联网向专有软件发出宣战。
X Windows 是首批由服务于全球各地不同组织的许多个人以团队形式开发的大规模开源项目之一。电子邮件使创意得以在这个群体中快速传播问题由此得以快速解决而开发者可以人尽其才。软件更新可以在数小时之内发送到位使得每个节点在整个开发过程中步调一致。网络改变了软件的开发模式。
另一方面RMS 的理论体系有许多东西非常有争议他的 GPL 被认为是一种 “病毒式” 的协议BSD 的 fans 和老牌 Unix 黑客们认为他们编写 Unix 的年头都比 GPL 声明要长得多GPL 依然有太多的限制而 BSD 协议则比 GPL 更加的自由。另一方面RMS 走向了另一个极端他是完全反版权的反商业化的。把软件产品从强制收费推向了强制免费、共享和开源这也为他带来了许多许多的争议。
在 RMS 组织黑客闹革命的年代里没有多少黑客认同于 RMS 的理论体系更多的他们参与 GNU 只是为了体现那种在互联网上协同工作令人激动的工作模式。自从 GNU 设立以来争议不断而黑客文化却从未有统一在他的理想体系之下。
自从 Linux 出现以后一个新的黑客领袖出现了Linus Torvalds 的中庸态度网聚了世界上顶尖的黑客其绕过了 GPL 和反 GPL 的派系之争他使用 GNU 的工具从而以 GPL 的 “传染性” 保护了 Linux但他同时也不承认 RMS 的理论思想体系他即开源又支持商业化。虽然他没有带给黑客们什么重要的思想体系或统一的价值观但他整合了全世界黑客的阵营让所有的黑客的行为都围绕着 Linux 这一事物进行。他以 “用自由软件是因为它运行得更好” 轻而易举地盖过了 “用自由软件是因为所有软件都该是自由的”。
1998 年初这种新思潮促使网景公司Netscape Communications公布了其 Mozilla 浏览器的源码。媒体对此事件的关注促成了 Linux 在华尔街的上市推动了 19992001 年间科技股的繁荣。事实证明此事无论对黑客文化的历史还是对 Unix 的历史都是一个转折点。
Unix 的历史教训
下面的文字出自《The Art of Unix Programming》Unix 编程艺术。令今天我们所有人所反思。
在 Unix 历史中最大的规律就是 看看《谁写了 Linux》你就会知道这一规律
距开源越近就越繁荣。任何将 Unix****专有化的企图只能陷入停滞和衰败。
回顾过去我们早该认识到这一点。1984 年至今我们浪费了十年时间才学到这个教训。如果我们日后不思悔改可能还得大吃苦头。
虽然我们在软件设计这个重要但狭窄的领域比其他人聪明但这不能使我们摆脱对技术与经济相互作用影响的茫然而这些就发生在我们的眼皮底下。即使 Unix 社区中最具洞察力、最具远见卓识的思想家他们的眼光终究有限。对今后的教训就是过度依赖任何一种技术或者商业模式都是错误的—— 相反保持软件及其设计传统的的灵活性才是长存之道。
另一个教训是别和低价而灵活的方案较劲。或者换句话说低档的硬件只要数量足够就能爬上性能曲线而最终获胜。经济学家 Clayton Christensen 称之为 “破坏性技术”他在《创新者窘境》The Innovator’s Dilemma[Christensen] 一书中以磁盘驱动器、蒸汽挖土机和摩托车为例阐明了这种现象的发生。当小型机取代大型机、工作站和服务器取代小型机以及日用 Intel 机器又取代工作站和服务器时我们也看到了这种现象。开源运动获得成功正是由于软件的大众化。Unix 要繁荣就必须继续采用吸纳低价而灵活的方案的诀窍而不是去反对它们。
最后旧学派的 Unix 社区因采用了传统的公司组织、财务和市场等命令机制而最终未能实现 “职业化”。只有痴迷的 “黑客” 和具有创造力的怪人结成的反叛联盟才能把我们从愚蠢中拯救出来 —— 他们接着教导我们真正的专业和奉献精神正是我们在屈服于世俗观念的 “合理商业做法” 之前的所作所为。
Unix 族谱
Unix 的故事仍旧延续着……许多网站也为这段历史留下记录。一个详细记录 Unix 历史的网站http://www.levenez.com/unix/这个网站忠实记载着 19692005 年 Unix 发展的大事而且还有 PDF 档案可供下载上面有一个庞大的 UNIX 家族版本树让人叹为观止。网站的首页陈列每个时期 Unix 的历史也代表着无数工程师的心血与努力。
下面是一个简单的 Unix 的族谱 |--ATT (1969)-----\| || V6 (1976)| || V7 (1979)| || Novell owns ATTs Unix (by 1994)| _____________|____________________| | | | | || AIX IRIX SCO HP-UX Solaris 2.X| (IBM) (SGI) (HP) (Sun)|||--Berkley (1977)-----\| || 1BSD (1977)
UNIX-| || 4.4BSD (1993)| || Net/2| || 4.4BSD-Lite (by 1995)| ________________|____________________________________| | | | | | || SunOS Ultrix NetBSD OSF/1 NeXTSTEP Mac OS X| (Sun) (DEC) (Various) (DEC) (NeXT) (Apple)| (FreeBSD)|||--Hybrids----\|Linux (Various)||____________________________________________| | | | | || RedHat Debian Mandrake Slackware S.u.S.E.| (Walnut Creek)||_____________________________________________| | | | |MkLinux LinuxPPC TurboLinux OpenLinux CorelLinux(Apple) (Caldera) (Corel)点些查看《Linux 分发包族谱》
Unix 的特点
现在的文献中提到 Unix 基本上是说由 Ken Thompson 和 Dennis Ritchie 共同开发的。而通过历史我们也能发现Unix 的主要是由 Ken Thompson 写下的。但在学术界Dennis Ritchie 的名字往往被排在了 Ken Thompson 前面的。这就是因为Dennis Ritchie 不但发明了 C 语言而且当时他设计 Unix 操作系统的设计思想影响了整个世界直到今天。
当时他们开发 UNIX没有正式立项是 Ken Thompson 和 Dennis Ritchie 等少数几个人偷偷干的如果一切都要从头从新设计那几乎是不可能的。所以Unix 吸取与借鉴了 Multics 的经验如内核进程层次式目录面向流的 I/O把设备当作文件…… 等等。但是 Unix 在继承中又有创新比如 Unix 采用一种无格式的文件结构文件由字节串加 \0 组成。这带来两大好处一是在说明文件时不必加进许多无关的 “填充物”二是任何程序的输出可直接用作其他任何程序的输入不必经过转换。后面这一点叫做 “管道”(piping)这就是 Unix 首创的。此外像把设备当作文件从而简化了设备管理这一操作系统设计中的难题虽然不是 UNIX 的发明但是实现上它采用了一些新方法比 Multics 更高明一些。
下面是 Unix 的特点30 多年过去了这些东西早已变成经典 Everything (including hardware) is a file 所有的事物甚至硬件本身都是一个的文件。 Configuration data stored in text 以文本形式储存配置数据。 Small, single-purpose program 程序尽量朝向小而单一的目标设计 Avoid captive user interfaces 尽量避免令人困惑的用户接口 Ability to chain program together to perform complex tasks 将几个程序连结起来处理大而复杂的工作。
Unix 的影响和哲学
Unix 是第三次工业革命中计算机软件领域最具代表性的产物。在这近 40 年中由 Unix 造成的影响是最有深远意义的。就我看来Unix 为软件领域带来了至少以下有积极的东西由这些东西所引发的直接或间接的事物更是举不胜数。
软件开发的若干哲学和思想。全民参与推动软件代码共享的模式。开启了黑客文化和开源项目。免费和商业的完美结合的 Linux。C 语言而后发展的 CJava 等等类 C 的语言和脚本。参看《C 语言的演变史》见下文TCP/IP其的 Socket 编程已成为今天通用的网络编程主流。参看《到处都是 Unix 的胎记》见下文
不能不说ATT 虽然发展了 Unix但今天 Unix 的混乱的局面也和 ATT 有着直接原因。但反过来说如果没有 ATT 的反面教材今天的 GNU/Linux 很有可能也不会出现。ATT 究竟是限制了 Unix 的发展还是以反面示例促进了 Unix 社区已不好评说。今天软件是商业化好还是开源好的争论还在继续纵观这几十年来 Unix 的历史Linux 的划时代地出现。相信你会得出自己的结论。不管怎么样Unix 的经历对计算机领域贡献的不单单是技术他给我们提供了丰富而生动的教材。特别是 Unix 引发的哲学让今天的我们依然受益不浅。
说到 Unix 为我们所带来的软件开发的哲学我必需要说一说。Unix 遵循的原则是 KISSKeep it simple, stupid。在 http://en.wikipedia.org/wiki/Unix_philosophy 上有很多的基本上大同小异的 Unix 哲学都是很经典的。
Doug McIlroy 是认为 UNIX 的哲学是这样的三条哲学简明扼要就是这三条哲学贯穿着整个 Unix 世界。尤其是第一条 “do one thing and do it well” 真是相当精彩
Write programs that do one thing and do it well.Write programs to work together.Write programs to handle text streams, because that is a universal interface.
只要是 Unix 的程序员他们会比别的程序员在任何时候都会不停地强调着这三条哲学。
而《The Art of Unix Programming》总结了下面这些哲学都是至理名言啊。
Rule of Modularity: Write simple parts connected by clean interfaces.Rule of Clarity: Clarity is better than cleverness.Rule of Composition: Design programs to be connected to other programs.Rule of Separation: Separate policy from mechanism; separate interfaces from engines.Rule of Simplicity: Design for simplicity; add complexity only where you must.Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.Rule of Transparency: Design for visibility to make inspection and debugging easier.Rule of Robustness: Robustness is the child of transparency and simplicity.Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.Rule of Least Surprise: In interface design, always do the least surprising thing.Rule of Silence: When a program has nothing surprising to say, it should say nothing.Rule of Repair: When you must fail, fail noisily and as soon as possible.Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.Rule of Optimization: Prototype before polishing. Get it working before you optimize it.Rule of Diversity: Distrust all claims for “one true way”.Rule of Extensibility: Design for the future, because it will be here sooner than you think.
X Windows 的设计者 Mike Gancarz 给出了下面九条哲学思想
1.Small is beautiful. 2.Make each program do one thing well. 3.Build a prototype as soon as possible. 4.Choose portability over efficiency. 5.Store data in flat text files. 6.Use software leverage to your advantage. 7.Use shell scripts to increase leverage and portability. 8.Avoid captive user interfaces. 9.Make every program a filter.
在今天这种思想依然被传承着在影响着世界上各个角落的每一个程序员。
Unix 痛恨者手册
这里还需要值得一提的是一本叫《The Unix-Haters Handbook》中文译做《Unix 痛恨者手册》。可以在这里下载http://research.microsoft.com/~daniel/uhh-download.html 其中以调侃的语气声讨了 Unix 的种种不是。虽然这是十年前的一本书了但还是值得一读。这本书指出了许多 Unix 的设计错误指出了种种看起来很合理的设计走向了荒谬还这样调侃了 C 语言 ——“如果说 C 语言给足了让你上吊的绳子那么C 在给了你足够的绳子把你的邻居全部捆起来之后还给了你足够的绳子让你为一艘小帆船装上帆最后你还有足够的绳子把自己吊死在帆船的桅杆上”。呵呵相当的尖酸刻薄吧。里面有一句对操作系统的评价是这样的“The fundamental difference between Unix and the Macintosh operating system is thatUnix was designed to please programmers, whereas the Mac was designed to please users. (Windows, on the other hand, was designed to please accountants.”Windows 设计给会计人员连计算机用户都不是了hh
不过我可以感觉得到这本书的作者在书中对 Unix 的感情是比较复杂的爱恨交加在书的最后有这样一句话 “would anyone have spent this much time and effort writing about how much they hated Unix if they didn’t secretly love it? I’ll leave that to the readers to judge, but in the end, it really doesn’t matter: If this book doesn’t kill Unix, nothing will”。是的如果 Unix 能够存活这么长的时间那么不会有什么东西可以把他消灭了。
从《Unix 痛恨者手册》这本书再加上 Unix 的历史我们可以感到 Unix 的经历的风风雨雨在 Unix 上面出现有种种教训近 40 年的历程Unix 历经磨难几近夭折一路走来的确很不容易让人由衷感叹。今天的 Unix今天的软件工业和以前相比已是不可同日而语。很大程度上这些都要归功于这个充满苍桑的 Unix。
后记
在中国我们开始学习计算机的时候我们被 Microsoft 所创造的文化所笼罩里。就在 Unix 出现革命性的转变在 Unix 影响计算机世界文化的那几年里科班出生专业开发人员学习的是 MS-DOS 和微软的文化我们犹如一个井底之蛙一样对外面的翻天覆地的变化无动于衷。微软创造的文化在我们这里尤其地根深蒂固我们几乎忘记了另外一边的 Unix参看《Unix 40 年Unix 年鉴》、《Unix 40 年昨天今天和明天》。
在那充满激情的 Unix 的岁月里大伙为了科研目的或个人兴趣在 Unix 上进行各种开发并且不计较金钱利益将这些源码公开互相共享。在那里开发和自由成为主题正因为如此当今的世界才如此丰富多采。在 40 年 Unix 文化和技术积淀的里面蕴涵着比较纯正的计算机文化和思想。
纵观整个 Unix 的历史过程中许许多多的程序员、工程师前辈们在 Unix 中所摸爬滚打他们的辛勤地、他们呕心沥血地跟随 Unix努力建立一个繁荣的计算机世界的文明。Unix 不是一个简简单单的操作系统。有人说Unix 是程序员设计给程序员的一点没错。Unix 的近 40 年历史造就了它的博大精深它给程序员们带来的绝不仅仅只是技术上的知识。它的失误它的无奈它的精神它的荣耀它从技术和思想上都启迪着我们。对于程序员来说学习 Unix 就等同于向前辈程序学习。无论你是什么样的程序员你都应该了解 Unix这是开发人员的根前面的开发者造就了它而它又在引领后面的开发人员它是前辈程序员们交给我们的一份礼物一个接力棒它是开发人员赖以生存的土壤是上一辈程序员留给我们这一代程序员开启未来的钥匙。Unix 就像一个程序员教父一样理当受到我们的尊敬和崇拜。
参考资料
Peter H. Salus 的《A Quarter Century of UNIX》这被认为是 UNIX 的标准历史。Eric S. Raymond 的《The Art of Unix Programming》http://www.wikipedia.org/ 维基百科http://www.computerhope.com/history/ Computer Historyhttp://www.lotsir.com/Blog/article.asp?id494 Lotsir’s Blog — 《UnixLinux 历史重温》http://www.aka.org.cn/Docs/hacker-history.html 《黑客文化简史》http://www.simson.net/ref/ugh.pdf 《The UNIX-HATERS Handbook》http://free-electrons.com/doc/free_software/img0.html 《GNU/Linux Free Software》幻灯片http://cm.bell-labs.com/cm/cs/who/dmr/hist.htmlDennis M. Ritchie《The Evolution of the Unix Time-sharing System》 谁写了 Linux
2009 年 08 月 25 日 陈皓
2009 年 8 月Linux 软件基金会 发布了一份叫《Who Writes Linux and Who Supports It》(PDF) 的报告。这份报告主要对 Linux 2.6.x 的开发进行了全方位的统计。看了以后才知道原来 Linux 的开发的生产率竟是这样的惊人而且相当的的令人振奋所以在第一时间转过来给大家看看。让人不得不惊叹这不可思议的具有非凡活力的社区。注意我们这里说的是 Linux不是 GNU 的那些东西所谓 Linux 就是 Linux 的 Kernel
下面是一个导读希望每一个看到这篇文章的朋友都能看看原文的报告《Who Writes Linux and Who Supports It》(PDF)
这份报告的一开始就对 Linux 的开发进行了总结
每 2-3 个月一个 release最近的每一次 release 都超过 10000 个补丁有超过 1000 个开发人员进行开发他们来自 200 个公司或组织。自 2005 年以来超过 5000 个来自 500 个不同公司的开发人员为 Linux 内核做过贡献。自 2008 年以来每次 release都大约增加了 10% 左右的开发人员而且代码码达到了 2.7 百万行。
是的这样的生产率真是太疯狂了。下面是这份文档中所涉及的一些介绍和一些具体的统计数据。
Linux 开发模式
Linux 的开发采用的是一种宽松的基于时间的开发模式。每一个新的主要版本的 release 基本上会发生在 2-3 个月之内。这个开发模式是在 2005 年形成的因为任何人都可以修改其内核的代码所以很多补丁进入内核的时间非常的快。
其中一个有意义的事是他们有一个叫 Linux-Next 的服务器这个服务器一般来说会是下一个版本的 staging比如如果目前的稳定版本是 2.6.31那么 Linux-Next 上就会运行 2.6.32。这样所有的 developer 都能看到下一个版本总体的样子而且这更容易发现一些集成性的问题。
在 2.6 的 mainline 代码库上mailline 是代码库的主线有一个叫做 “stable team” 的团队他们会做短期的维护工作他们确保所有的重要的补丁或更改都会被放入 mailline 中这样就能滚入下一个 release。
然后这份文档中给出了大量的开发编译数据。
统计数据
下面的统计数据是从版本 2.6.11 开始的我把源文件中的表格合并成一个大表如下所示。 从上图我们可以看到下面这些东西
Linux Kernel 开发的速度越来越快看看每个 release 的补丁数每天文件增、删、改就可以知道。Linux Kernel 开发的团队是越来越大包括人员和参与的公司。
下面是几个统计图表 平均每天的修改 代码修改统计 开发人员
谁写了 Linux
最后我们进入主题 —— 谁写了 Linux首先我们先来看一下进入代码修改的 Top 30 的开发人员列表 我们可以看到Linus Torvalds 729 总修改自 2.6.24 版来 254 修改无法进入前 30 名。当然对 Linux 的贡献绝对不能通过代码行来表示Linus 对 Linux 就算是在今天也是至关紧要的。
好让我们再来看看那些公司对 Linux 的贡献。根据这份报告所说知道每个 developer 所在的公司主要是通过了下面的几种方法
使用的邮件地址有公司的名字。由赞助者提交的代码。直接询问得到的。
所以这些数据只能算得上的近似不过也能看到一个总体的样子了。下图中 “None” 代表没有职业无业游民“Unknown” 代表无名氏或是英雄不知出处。 我们可以看到Top 10 公司为 Linux 贡献了近 70% 的代码。包括了 None 和 Unknown而且那些是拿着公司报酬给 Linux 作开发的程序员。
那么为什么这些公司要支持 Linux 的内核开发呢
我们可以看到像 IBM, Intel, SGI, MIPS, Freescale, HP, Fujitsu 这样的大公司他们的目的当然是为了确保 Linux 能够在他们的硬件上工作得更好。我们也可以看到像 Red Hat, Novell, 和 MontaVista 这些 Linux 的 Distribution 公司他们是 Linux 的主力主要是为了提供给他们的客户更好的服务。同样我们还能看到像 Sony, Nokia, 和 Samsung 这样的公司这些公司主要是用 Linux 来开发数码产品如摄像机、手机或是电视他们使用 Linux 做一些嵌入式开发以保证他们的产品工作得更好。还有一些和 IT 都没有关系的例如Volkswagen 公司在 v21.6.25 中为 Linux 加入了 PF_CAN 网络实现的协议。Quantum Controls BV 公司在 2.6.30 时加入了一个航海导航的补丁这些公司都会使用 Linux 来完善他们的产品。
看来Linux 的势头是越来越无法阻挡了你也想加入这个阵营吗点下面的链接吧http://ldn.linuxfoundation.org/book/how-participate-linux-community
全文完 Alice 梦游 UNIX 仙境
2009 年 09 月 19 日 陈皓
本文来源http://www.pma.caltech.edu/Publications/alice.in.unix.land.html 这是一篇 1989 年的文章
Alice 正在在她的显示器上读着一些信息她开会怀疑所有的事情并不是应该的那样。“程序太大了而无法适应内存”她读到。
“一个很奇怪的事情”她说“我所做的也就是在启动我的字处理程序会运行了 14 个 TSRterminate-and-stay-resident 常驻程序。所有这些程序需要使用 4M 的内存我希望我能使用超过 640K 以上的内存”。
就在那个时候一个小的白色的顾问一个非常白的顾问跑过了房间。“哦我的外套和领带”他说到“我要迟到了。并且是每小时 150 元。”Alice 本想对他说点什么他却跳到了 Alice 的显示器里并到在操作系统后面消失了。
Alice 从来没有见过有人可以跳到显示器里并且肯定不是通过操作系统干。但是曾有人告诉他DOS 这个操作系统是非常肤浅的。于是她没有怎么犹豫Alice 也跳了进去。
Alice 发现她自己在一个明亮的走廊里。她不知道要做什么她开始向前走走过了一个拐角后她发现她的前面有两个小胖子他们互相搂着对对方的脖子。一个人的领口上绣着 “POS”另一个则是 “NEG”。
“我知道”Alice 说“你俩是晶体管”。
“是的”Positive 回答到。
“你们能帮我吗”Alice 问道。
“不能”Negative 回答。
“我在找一个白色的顾问”Alice 指着她走过来的方向“他走的是这条路吗”Alice 继续问道。
“不是”Negative 回答到。
Alice 又指了另一条路。
“是的”Postive 回答到。
很快Alice 来到了一个很大的棕色的桌前。那个顾问就在那里名字叫 Mad Hacker并且有一些 Alice 并不知道的生物围在桌边。在角落里有一个睡鼠在那熟睡。在桌子上放着一个大的标牌 上面写着 “UNIX Conference”
每一个人除了那只睡鼠都有一个纸杯纸杯里应该是奶油蛋羹的样子。“错误的佐料”他们所有人都这么说并把杯子传递给他们右手边的人并且优雅地从他们的左边接过杯子。Alice 看着他们重复着这个仪式三到四次后她也坐到了他们中间。
马上一个很大的癞蛤蟆跳到了他的大腿上并看着她就好像希望得到 Alice 的宠爱。“Grep”它叫到。
“别介意”Mad Hacker 解释道“他只是想查找一些字符串”。
“Nroff” 蛤蟆问到。
Mad Hacker 给了 Alice 一个有看似有奶油蛋羹杯子以及一把勺子。“这里”他问到“你对这个有什么想法”
“看起来很可爱”Alice 说“非常甜”。她边说边尝了一勺。“讨厌” 他叫到“真糟糕这是什么啊”
“哦这只不过是 Unix 的另一个图形界面”Hacker 回答道。
Alice 指着角落里的那只睡鼠说“他是谁”
“那也是一个操作系统”Hacker 解释道“我们几乎放弃了去把他唤醒过来”。
就在这个时候坐在睡鼠旁边的一个很大的蓝色的大象站了起来。“女士们先生们”他很傲慢地说到“作为在这里的一个最大的生物我感到我们必需开明地来看一下……”
一个在桌子另一边的年轻的 “工作麻雀” 愤努地站了起来。大象注意这事并改变了他的演讲“…… 什么是我们下一步的行动”。
有一半的生物鞠躬至敬而另一半的生物偷偷窃笑。这个时候睡鼠醒过来了要和这个大象合并。没人有一丁点的惊讶。
“我们需要什么”一只 Sun 熊宣称他用他的长甜头舔了舔那个奶油蛋羹说道“我们需要的是一个像 Macintosh 那样的调料”。
突然那个白色顾问红着脸跳了起来“不不不” 他尖叫着“没有人会 150 元一小时的费用给 Macintosh”
“Awk”青蛙说道。
“用户”Sun 熊解释到“用户们希望的是那种简单到不需要学习的用户接口”。
“用户”Hacker 叫到 “用户你说的是那些秘书会计建筑师以及体力劳动者”
“喔” Sun 熊说到“我得做点什么得让他们把系统切换到 UNIX”。
“你们是否觉得” 一个正在桌子上打洞的啄木鸟说“我们一同使用 Unix 这个名字会是一个问题我的意思是这样想的并不只有我一个人。”
“也许我们应该试试别的名字”工作麻雀说“比如Brut 或 Rambo”。
“Penix” 一只企鹅说到。
“mount”蛤蟆说“spawn”。
Alice 拍了一下蛤蟆。“nice?” 蛤蟆问到。
“但是”啄木鸟又建议到“ShrinkWap 的问题怎么办”
突然每一个人都跳了起来而且都变得活跃起来挥动着他们的双手大叫着但只一会他们又全都坐下来。
“现在这个问题解决了”啄木鸟说“让我们回到调料的问题上来吧”。
于是桌子边的每个人又采样了一个新的奶油蛋羹继续说到 “错误的调料”然后把杯子传给右边的人并从左边的人接过杯子。
完全地被搞糊涂了Alice 起身离开了她正在正在离开的过程中她听到了身后传来了一个熟悉的声音。
“rem”它说“edlin”
Alice 转过身去看到了那只蛤蟆她微笑着。“你总是说着这些古怪发音的单词”她说“但至少我知道他们是什么意思”。
“chkdsk” 蛤蟆说到。
—–By Lincoln Spector TEXAS COMPUTER CURRENTS SEPTEMBER 1989 到处都是 Unix 的胎记
2009 年 10 月 11 日 陈皓
一说起 Unix 编程不必多说最著名的系统调用就是 forkpipeexeckill 或是 socket 了fork(2), execve(2), pipe(2), socketpair(2), select(2), kill(2), sigaction(2)这些系统调用都像是 Unix 编程的胎记或签名一样表明着它来自于 Unix。
下面这篇文章将向大家展示 Unix 下最经典的 socket 的编程例子 —— 使用 fork socket 来创建一个 TCP/IP 的服务程序。这个编程模式很简单首先是创建 Socket然后把其绑定在某个 IP 和 Port 上上侦听连接接下来的一般做法是使用一个 fork 创建一个 client 服务进程再加上一个死循环用于处理和 client 的交互。这个模式是 Unix 下最经典的 Socket 编程例子。
下面让我们看看用 CRubyPythonPerlPHP 和 Haskell 来实现这一例子你会发现这些例子中的 Unix 的胎记。如果你想知道这些例子中的技术细节那么向你推荐两本经典书 ——《Unix 高级环境编程》和《Unix 网络编程》。
C语言
我们先来看一下经典的C是怎么实现的。
/**\* A simple preforking echo server in C.*\* Building:*\* $ gcc -Wall -o echo echo.c*\* Usage:*\* $ ./echo*\* ~ then in another terminal ... ~*\* $ echo Hello, world! | nc localhost 4242**/
#include unistd.h /* fork, close */
#include stdlib.h /* exit */
#include string.h /* strlen */
#include stdio.h /* perror, fdopen, fgets */
#include sys/socket.h
#include sys/wait.h /* waitpid */
#include netdb.h /* getaddrinfo */#define die(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define PORT 4242
#define NUM_CHILDREN 3
#define MAXLEN 1024int readline(int fd, char *buf, int maxlen); // forward declarationint
main(int argc, char** argv)
{int i, n, sockfd, clientfd;int yes 1; // used in setsockopt(2)struct addrinfo *ai;struct sockaddr_in *client;socklen_t client_t;pid_t cpid; // child pidchar line[MAXLEN];char cpid_s[32];char welcome[32];/* Create a socket and get its file descriptor -- socket(2) */sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd -1) {die(Couldnt create a socket);}/* Prevents those dreaded Address already in use errors */if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)yes, sizeof(int)) -1) {die(Couldnt setsockopt);}/* Fill the address info struct (host port) -- getaddrinfo(3) */if (getaddrinfo(NULL, PORT, NULL, ai)! 0) {die(Couldnt get address);}/* Assign address to this sockets fd */if (bind(sockfd, ai-ai_addr, ai-ai_addrlen)! 0) {die(Couldnt bind socket to address);}/* Free the memory used by our address info struct */freeaddrinfo(ai);/* Mark this socket as able to accept incoming connections */if (listen(sockfd, 10) -1) {die(Couldnt make socket listen);}/* Fork you some child processes. */for (i 0; i NUM_CHILDREN; i) {cpid fork();if (cpid -1) {die(Couldnt fork);}if (cpid 0) { // Were in the child...for (;;) { // Run forever.../* Necessary initialization for accept(2) */client_t sizeof client;/* Blocks! */clientfd accept(sockfd, (struct sockaddr *)client, client_t);if (clientfd -1) {die(Couldnt accept a connection);}/* Send a welcome message/prompt */bzero(cpid_s, 32);bzero(welcome, 32);sprintf(cpid_s, %d, getpid());sprintf(welcome, Child %s echo , cpid_s);send(clientfd, welcome, strlen(welcome), 0);/* Read a line from the client socket... */n readline(clientfd, line, MAXLEN);if (n -1) {die(Couldnt read line from connection);}/*... and echo it back */send(clientfd, line, n, 0);/* Clean up the client socket */close(clientfd);}}}/* Sit back and wait for all child processes to exit */while (waitpid(-1, NULL, 0) 0);/* Close up our socket */close(sockfd);return 0;
}/*** Simple utility function that reads a line from a file descriptor fd,* up to maxlen bytes -- ripped from Unix Network Programming, Stevens.*/
int
readline(int fd, char *buf, int maxlen)
{int n, rc;char c;for (n 1; n maxlen; n) {if ((rc read(fd, c, 1)) 1) {*buf c;if (c \n)break;} else if (rc 0) {if (n 1)return 0; // EOF, no data readelsebreak; // EOF, read some data} elsereturn -1; // error}*buf \0; // null-terminatereturn n;
}Ruby
下面是 Ruby你可以看到其中的 fork
# simple preforking echo server in Ruby
require socket# Create a socket, bind it to localhost:4242, and start listening.
# Runs once in the parent; all forked children inherit the sockets
# file descriptor.
acceptor Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
address Socket.pack_sockaddr_in(4242, localhost)
acceptor.bind(address)
acceptor.listen(10)# Close the socket when we exit the parent or any child process. This
# only closes the file descriptor in the calling process, it does not
# take the socket out of the listening state (until the last fd is
# closed).
#
# The trap is guaranteed to happen, and guaranteed to happen only
# once, right before the process exits for any reason (unless
# its terminated with a SIGKILL).
trap(EXIT) { acceptor.close }# Fork you some child processes. In the parent, the call to fork
# returns immediately with the pid of the child process; fork never
# returns in the child because we exit at the end of the block.
3.times dofork do# now were in the child process; trap (Ctrl-C) interrupts and# exit immediately instead of dumping stack to stderr.trap(INT) { exit }puts child #$$ accepting on shared socket (localhost:4242)loop {# This is where the magic happens. accept(2) blocks until a# new connection is ready to be dequeued.socket, addr acceptor.acceptsocket.write child #$$ echo socket.flushmessage socket.getssocket.write messagesocket.closeputs child #$$ echod: #{message.strip}}exitend
end# Trap (Ctrl-C) interrupts, write a note, and exit immediately
# in parent. This trap is not inherited by the forks because it
# runs after forking has commenced.
trap(INT) { puts \nbailing ; exit }# Sit back and wait for all child processes to exit.
Process.waitallPython实现代码 Simple preforking echo server in Python.import os
import sys
import socket# Create a socket, bind it to localhost:4242, and start
# listening. Runs once in the parent; all forked children
# inherit the sockets file descriptor.
acceptor socket.socket()
acceptor.bind((localhost, 4242))
acceptor.listen(10)# Ryans Ruby code here traps EXIT and closes the socket. This
# isnt required in Python; the socket will be closed when the
# socket object gets garbage collected.# Fork you some child processes. In the parent, the call to
# fork returns immediately with the pid of the child process;
# fork never returns in the child because we exit at the end
# of the block.
for i in range(3):pid os.fork()# os.fork() returns 0 in the child process and the childs# process id in the parent. So if pid 0 then were in# the child process.if pid 0:# now were in the child process; trap (Ctrl-C)# interrupts by catching KeyboardInterrupt) and exit# immediately instead of dumping stack to stderr.childpid os.getpid()print(Child %s listening on localhost:4242 % childpid)try:while 1:# This is where the magic happens. accept(2)# blocks until a new connection is ready to be# dequeued.conn, addr acceptor.accept()# For easier use, turn the socket connection# into a file-like object.flo conn.makefile()flo.write(Child %s echo % childpid)flo.flush()message flo.readline()flo.write(message)flo.close()conn.close()print(Child %s echod: %r % (childpid, message.strip()))except KeyboardInterrupt:sys.exit()# Sit back and wait for all child processes to exit.
#
# Trap interrupts, write a note, and exit immediately in
# parent. This trap is not inherited by the forks because it
# runs after forking has commenced.
try:os.waitpid(-1, 0)
except KeyboardInterrupt:print(\nbailing)sys.exit()Perl实现代码
#!/usr/bin/perl
use 5.010;
use strict;
# simple preforking echo server in Perl
use Proc::Fork;
use IO::Socket::INET;sub strip { s/\A\s//, s/\s\z// for my r _; r }# Create a socket, bind it to localhost:4242, and start listening.
# Runs once in the parent; all forked children inherit the sockets
# file descriptor.
my $acceptor IO::Socket::INET-new(LocalPort 4242,Reuse 1,Listen 10,
) or die Coulnt start server: $!\n;# Close the socket when we exit the parent or any child process. This
# only closes the file descriptor in the calling process, it does not
# take the socket out of the listening state (until the last fd is
# closed).
END { $acceptor-close }# Fork you some child processes. The code after the run_fork block runs
# in all process, but because the child block ends in an exit call, only
# the parent executes the rest of the program. If a parent block were
# specified here, it would be invoked in the parent only, and passed the
# PID of the child process.
for (1.. 3) {run_fork { child {while (1) {my $socket $acceptor-accept;$socket-printflush(child $$ echo );my $message $socket-getline;$socket-print($message);$socket-close;say child $$ echod: ${\strip $message};}exit;} }
}# Trap (Ctrl-C) interrupts, write a note, and exit immediately
# in parent. This trap is not inherited by the forks because it
# runs after forking has commenced.
$SIG{INT} sub { print bailing\n; exit };# Sit back and wait for all child processes to exit.
1 while 0 waitpid -1, 0;PHP实现代码
?php
/*
Simple preforking echo server in PHP.
Russell Beattie (russellbeattie.com)
*//* Allow the script to hang around waiting for connections. */
set_time_limit(0);# Create a socket, bind it to localhost:4242, and start
# listening. Runs once in the parent; all forked children
# inherit the sockets file descriptor.
$socket socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket,localhost, 4242);
socket_listen($socket, 10);pcntl_signal(SIGTERM, shutdown);
pcntl_signal(SIGINT, shutdown);function shutdown($signal){global $socket;socket_close($socket);exit();
}# Fork you some child processes. In the parent, the call to
# fork returns immediately with the pid of the child process;
# fork never returns in the child because we exit at the end
# of the block.
for($x 1; $x 3; $x){$pid pcntl_fork();# pcntl_fork() returns 0 in the child process and the childs# process id in the parent. So if $pid 0 then were in# the child process.if($pid 0){$childpid posix_getpid();echo Child $childpid listening on localhost:4242 \n;while(true){# This is where the magic happens. accept(2)# blocks until a new connection is ready to be# dequeued.$conn socket_accept($socket);$message socket_read($conn,1000,PHP_NORMAL_READ);socket_write($conn, Child $childpid echo $message);socket_close($conn);echo Child $childpid echod: $message \n;}}
}#
# Trap interrupts, write a note, and exit immediately in
# parent. This trap is not inherited by the forks because it
# runs after forking has commenced.
try{pcntl_waitpid(-1, $status);
} catch (Exception $e) {echo bailing \n;exit();
}Haskell实现代码
import Network
import Prelude hiding ((-))
import Control.Monad
import System.IO
import Control.Applicative
import System.Posix
import System.Exit
import System.Posix.Signalsmain :: IO ()
main with (listenOn - PortNumber 4242) wherewith socket doreplicateM 3 - forkProcess workwaitwherework doinstallHandler sigINT (Catch trap_int) Nothingpid - show $ getProcessIDputs - child pid accepting on shared socket (localhost:4242)forever - do(h, _, _) - accept socketlet write hPutStr hflush hFlush hgetline hGetLine hclose hClose hwrite - child pid echo flushmessage - getlinewrite - message \nputs - child pid echod: message closewait forever - do( const () $ getAnyProcessStatus True True ) catch const trap_exittrap_int exitImmediately ExitSuccesstrap_exit doputs \nbailingsClose socketexitSuccessputs putStrLn(-) ($)infixr 0 -如果你知道更多相关内容请告诉我们。全文完 C 语言的演变史
2009 年 12 月 21 日 陈皓
1972 – C 语言的先驱 ——B 语言被贝尔实验室开发。B 语言是一个很快速的容易维护的而且对于从系统到应用开发是很好用的。设计这门语言的整个团队被马上解雇了因为他们干了一件和电话通讯不相干的事情。最后这个项目转给了 Dennis Ritchie。他把这个语言变得不容易理解很难维护而且只能用于系统方面的编程。而且他还设计了一个指针系统保让每一个程序都超过 500 行并可以使用操作系统的指针。
1982 – 大家发现有 97% 的 C 程序调用产生了 “缓冲区溢出” 问题。于是C 程序员们开始意识到就算是不必要也必需要初始化变量。然而强制性的变量初始化这个明智的决定很难影响了当时已经写成了的 97% 的 C 程序所以结果什么也没有发生。
1984 – 操作系统出现了 “错误指针” 的问题数量开始戏剧性地增涨。
1985 – 一系列的让 C 语言有面向对象能力的解决方法出现了一个叫 “C With Classes” 正准备商业化。然而大家觉得名字 “C With Classes” 太清楚和容易被理解了所以最终的商业版本叫做 —— C。
1986 – C 语言成为最流行的语句其被很多业界分析师推荐于业务应用。他们向全世界宣称 —— 由 C 语言写成的应用将可以运行在很多不同的平台上的是跨平台的。目前看来这些众多的分析者在当时有可能是因为某种迷幻而导致其大脑被所蛊惑了。
1988 – 业界的这些分析家们因为 “摇头丸” 吃完了。所以在他们的幻觉过去以后他们注意到使用 C 语言来开发业务应用会增加 5 倍以上的开发时间并且程序也不具备可移植性。他们开始停止向大众推荐使用 C 语言来开发业务应用了只能很少一部服用可卡因的人开始转向推荐大众使用 C 语言写业务应用程序他们说“那是面向对象的所以代码是很容易重用的”。
1990 – 在这个时候所有的 C 编译器都转到了 C 编译器上。但是因为大多数的 C 程序员并没有使用 C 中那些面向对象的语言特性。也就是说在实际上来说那种浮肿的代码结构加上操作系统指针的代码被一种叫面向对象的编译器编译。
1990 – 在雇佣了一些转向 “吸胶毒” 的分析师后Sun 决定要创造一种叫 Oak 的语言这种语言主要用于电视的机顶盒。因为当时几乎所有的程序员的 DNA 中都有 C 语的基因所以这个语言向 C 和 C 中大量地借鉴了很多它们的语法和编程思路。然而机顶盒上没有操作系统也就不存在指针所以他们把指针从这门语言里给去掉了。
1994 – Sun 公司里的某个人意识到为一个机顶盒开发一个语言是多么愚蠢的事情。于是这个语言更名为 Java并且为其注入了 “Internet” 的特征从而让其成为一个真正可以被移植的语言。其市场营销上相当成功而那时有 3% 的业内人士开始明白什么是 Internet同时那些精神不正常的分析师们还在不停地嗑药并向大众鼓吹他们的神话 ——“跨平台移植性”。
1995 – Sun 向业界的分析师们提供了免费蘑菇迷魂汤导致那些分析师在喝下汤后马上开始写下 “Java 是一门未来的可移植的和 Ineternet 高度可集成的语言”。
1996 中 – 17,468,972 篇文章出现描述了 Java 是怎么一门未来的语言。这也是 Java Applet 开始进入 Web 页的时代。
1996 末– 程序员开始使用 Java applet 创建他们的 Web 页面然后他们开始因为挫折和沮丧开始集体自杀。此时那些分析师开始增大蘑菇迷魂汤的剂量。
1997 – 因为接受了产生幻觉分析师的建议Corel 决定重写他们的应用包括 WordPerfect当然是用 Java 写的。最终的结果是这是迄今为止比 “打字机” 还慢的字处理软件。
1998 – 在意识到 applet 已在快速枯萎Sun 又一次的重新配置了 Java这次他们叫 Severlet这是一个服务器的程序语言。这个设计在抄袭了 Microsoft Transaction Server 并且他们说服所有人这个设计是他们创造的。
1999 – 业内那些喝多了的分析师们用一种咆哮的方式向大众介绍了 Java 2 Enterprise Edition 。 21,499,512 文章被写出来。但是实际上并没有人使用因为 J2EE 太不成熟而又太贵了。
2000 – J2EE 最终还是运转起来了一点点。而且所有的 Java 卖主们开始准备向其砸钱与此同时Microsoft 宣布了.NET这是一个包括了所有的 J2EE 功能但没那么贵的产品。实际上来说 Microsoft 决定让 Windows 的用户免费使用.NET 。 Scott McNealy 很愤怒其对 Microsoft 开展了相关的法律诉讼。
.NET 包括了最新的 C 家族语言叫 C#发音是 “C-pound”继承最家族的传统使用着一个愚蠢的名字。
2001 – Microsoft 的市场部意识到在市面上没有人谈论他们的产品他们找了其中一个程序员一起吃中饭才发现他们把 C# 叫做 “C sharp”。
2002 – C# 成为 Microsoft .NET 的一部分。 C 的开发者在 Microsoft 平台上为 “managed code” 而欢呼雀跃也就是说他们最终得到了一个内存自动管理的功能这一功能正是 1991 年的 Visual Basic 及 1995 年的 Java 所创建的 。
copyright © 1996-2006 by Billy S. Hollis, originally posted on dotnetmasters.com 13 January 2006 via: Unix 传奇 (上篇) | 酷 壳 - CoolShell 2010年04月09日 陈皓 https://coolshell.cn/articles/2322.html Unix 传奇 (下篇) | 酷 壳 - CoolShell 2010年04月09日 陈皓 https://coolshell.cn/articles/2324.html 谁写了 Linux | 酷 壳 - CoolShell 2009 年 08 月 25 日 陈皓 https://coolshell.cn/articles/1360.html Alice梦游UNIX仙境 | 酷 壳 - CoolShell 2009 年 09 月 19 日 陈皓 https://coolshell.cn/articles/1439.html 到处都是 Unix 的胎记 | 酷 壳 - CoolShell 2009 年 10 月 11 日 陈皓 https://coolshell.cn/articles/1532.html C 语言的演变史 | 酷 壳 - CoolShell 2009 年 12 月 21 日 陈皓 https://coolshell.cn/articles/1984.html