作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!
我们以下图为基础,说明Linux的架构(architecture)。(该图参考《 Advanced Programming in Unix Environment》)
最内层是我们的硬件,最外层是我们常用的各种应用,比如说使用firefox浏览器,打开evolution查看邮件,运行一个计算流体模型等等。硬件是我们的物质基础,而应用是我们所要奋斗的目标,但在两者之间,还要经过一番周折。
还记得我们在 Linux启动的时候。首先会启动内核 (kernel),内核是一段计算机程序,这个程序直接管理管理硬件,包括CPU、内存空间、硬盘接口、网络接口等等。所有的计算机操作都要通过内核传递给硬件。
为了我们方便调用内核,我们将内核的功能总结成为系统调用(system call)。
系统调用看起来就像是的C语言函数——注意这点,就是c语言函数,因为linux是用这个写的
你也可以在程序中直接调用。Linux系统有两百多个这样的系统调用。系统调用给了上层程序一个清晰的接口,隐藏了内核的复杂结构。一个操作系统上的功能可以看作是系统调用的组合的效果,而且一个操作系统不可能作出超越系统调用的动作。可以说一个系统调用函数就像是汉字的一个笔画,任何一个汉字都要由基本的笔画(点、横、撇等等)构成,而且我们不能臆造出笔画。在命令行中输入$man 2 syscalls可以查看所有的系统调用。你也可以通过$man 2 read来查看系统调用read()的说明。在这两个命令中的2都表示我们要在2类(系统调用类)中查询 (具体各个类是什么可以通过$man man看到)。
怎么调用系统调用呢?
http://www.dedecms.com/knowledge/servers/linux-bsd/2012/0830/13550.html
一、使用标准C库函数,属于隐式调用
二、使用int syscall(int number, ...);
(在unistd.h里可以看到很多,并且可以看到,里面有/* POSIX.1-1990 */的标志,也就是说,这已经是函数库了
但是这个头文件是c语言的,而linux底层就是用c写的意思就是这个吗?就是说,linux的系统调用是用c来写的,而我们常用的c语言是对这些系统调用做了封装了)
system call例如我们熟悉的fork,getpid,getppid,曾记否操作系统实验课让我们用fork编程!那就是系统编程!
甚至可以看到reboot这种,我们平时在shell里面用的reboot,是应用程序,放在/sbin/reboot
shutdown也是,放在/sbin/shutdown
他们都封装了这些system call
下面这篇详细讲解了linux的启动过程
http://forum.ubuntu.org.cn/viewtopic.php?t=5408
(从这篇文章看到,所谓的看源码学linux,一部分就是各种源码,例如ls的实现等等,一部分就是看他们读取的文件,反正就是看代码——看代码才能理解工作流程,至于作者怎么理解内内核启动过程的,还不清楚)
可以去看下/sbin/shutdown的源码:
(这就是常说的看系统源码?文中还写到在本文对Linux启动过程的介绍中,我们也尝试从源代码的视角来更深入的剖析Linux 的启动过程,所以其中也简单涉及到部分相关的Linux源代码,Linux启动这部分的源码主要使用的是C语言,也涉及到了少量的汇编。而启动过程中也执行了大量的shell(主要是bash shell)所写脚本。)
我在FreeBSD的源代码里面找到了sbin/shutdown.c:
这些就是它的实现,里面就是各种c的系统调用了,编译出来就是sbin/shutdown
BSD源码的确是个宝库,mac也是用BSD的,而且,看源码要懂c,源码各种高质量
(Mach, which does the typical kernel work like memory management, scheduling and interprocess communication, BSD, which provides the POSIX-style syscall interface, file systems and networking to user mode, and I/O-Kit, the driver infrastructure written in C++. )
http://events.ccc.de/congress/2007/Fahrplan/events/2303.en.html
实质上为darwin,它由多种重要的技术组成,如FreeBSD、Mach、I/O Kit、网络、文件系统等。
http://www.elecfans.com/3g/TDSCDMA/20100130160390.html
我们linux上面用的man,用man reboot可以查到section 8的BSD System Manager's Manual的reboot,是应用程序,属于shell调用应用程序
而用man 2 reboot则是section 2的BSD System Calls Manual的reboot,是system call,系统调用,在mac os只有238个
而用man 3 sleep则是section 3的BSD Library Functions Manual,是库函数,在mac os有18000多个!
用man 1 ftp是section 1的BSD General Commands Manual,是通用指令
man 4 tcp是section 4的BSD Kernel Interfaces Manual,是内核接口,mac os共有40个,包括ip,ip6,tcp,udp等等,manual里面有注明,里面有说明The TCP protocol appeared in 4.2BSD.这种历史,说明mac os底层有一部分是BSD,大部分是系统调用的一部分而已,组成系统调用
(里面看到ip里面这行,#include <sys/socket.h>,就是说,所谓的从socket层开始编起,是指从系统调用开始编起?!之前认为python socket就是所说的socket编程的我真是太天真了。。。)
man 5 gbk是BSD File Formats Manual,文件格式手册,里面就一堆文件格式说明,例如gbk -- Guojia biaozhun kuozhan (GBK) encoding method for Chinese text,还有例如utf-8,big5
man 6 banner是BSD Games Manual,BSD游戏手册,运行游戏,输入信息,太牛逼,原来如此
man 7 COPY是PostgreSQL 9.3.5 Documentation,是SQL语句的手册?!还有SELECT。。卧槽
man 9 copy是BSD Kernel Developer's Manual,一些kernel的系统调用
unix系统编程用的是system call还是库函数?
从UNIX环境高级编程这本书的目录可以看出:
综合了库函数的使用和系统调用的使用,用什么,当然是c
由于系统调用非常基础,所以有时使用起来很麻烦。比如说一个简单的给变量分配内存空间的操作,就需要动用多个系统调用。Linux定义一些库函数(library routine)来将系统调用组合成某些常用的功能(section 3),以方便我们编程。比如上面的分配内存的操作,看以定义成为一个库函数(像malloc()这样的函数)。再比如说,在读取文件的时候,系统调用要求我们设置好所需要的缓冲。我们这个时候可以使用Standard IO库中的读取函数,而这个读取函数既负责设置缓冲,又负责使用读取的系统调用函数。使用库函数对于机器来说并没有效率上的优势,但可以把程序员从细节中解救出来。库函数就像是汉字的偏旁部首,它由笔画组成,但使用偏旁部首更容易组成字,比如"铁"。当然,你也完全可以不使用库函数,而直接调用系统函数,就像“人”字一样,不用偏旁部首。
(实际上,一个操作系统要称得上是UNIX系统,必须要拥有一些库函数,比如ISO C标准库,POSIX标准等。)
POSIX标准:是IEEE为要在各种UNIX操作系统上运行的软件,而定义API的一系列互相关联的标准的总称
linux为了兼容unix上面的软件,才写linux过程中也遵循POSIX标准
至于shell,可以看作一种特殊的应用。实际上我们之前所说的 命令行,就是shell。shell是一个命令解释器(interpreter),当我们输入ls的时候,它将此字符串解释为1) 在默认路径找到该文件(/bin/ls),2) 执行该文件。我们之前 用>表示重新定向,用|表示管道,也是通过shell进行理解&或者|的含义,再通过系统调用指挥kernel建立具体的重定向或者管道机制。在没有图形界面之前,shell充当了用户的界面,当用户要运行某些应用的时候,要通过shell输入命令,以建立运行程序。shell可以执行符合shell语法的文本,这样的文本叫做shell脚本(script)。
我们可以在图中看到,shell下通系统调用,上通各种应用,同时还有许多自身的便利可以使用,这些条件让shell脚本可以实现非常强大的功能。(我暂时找不到可以直接调用系统调用)
UNIX的一条哲学:
是让每个程序尽量独立的做好一个小的功能。(模块化)
而shell充当了这些小功能之间的"胶水",让不同程序能够以一个清晰的接口(文本流)协同工作,从而增强各个程序的功能。(这也是我们鼓励多用shell,少用图形化界面的原因之一。)
(shell也有很多种,最常见的是bash, 另外还有sh, csh, tcsh, ksh。它们出现的年代不同,所支持的功能也有差异。)
最后,我们进入一般的应用。应用是一个程序,它可以1) 直接调用系统函数 2) 调用库函数 3) 运行shell script。这些应用可以由多种语言开发(当然,最常见的是C语言),以满足我们使用计算机的各种需要。
我们可以看到,Linux利用kernel实现软硬件的对话。通过系统调用的这个重要的接口,Linux将上层的应用与下层的kernel完全分离开,为程序员隐藏了底层的复杂性(相应的,也提高了上层应用的可移植性)。当我们在升级kernel的时候,也可以保持系统调用的语句不变,从而让上层应用不感受到下层的改变。库函数利用系统调用创造出模块化的功能,而shell则提供了一个用户界面,并让我们可以利用shell的语法编写脚本,以整合程序。
而所有的这些安排也为其他应用的开发提供了便利。
总结:
kernel 系统调用
库函数 shell
应用
本文在作者原文基础上有改动,如要看作者原文,轻到http://www.cnblogs.com/vamei阅读,谢谢!