天呐,我有几天没写了啊?!这几天忙着专利第二稿的改写和论文的调研,已经无暇顾及我心爱的apue了。那今天,把第九章搞定吧!内容很简单~
第九章名称叫进程关系,也都是写理论和概念上的东西,讲了下面几个方面:终端登录和网络登录;session(会话);job control(作业控制)。
那就首先来看terminal(终端)。
这个词已经很熟悉了,显示器啊、键盘啊、鼠标啊都是终端,但我们常常听到几个词,你能搞清它们的区别吗?terminal?shell?tty?console?好啦,想看细节的点这里:What is the exact difference between a "terminal", a "shell", a "tty" and a "console"?(http://unix.stackexchange.com/questions/4126/what-is-the-exact-difference-between-a-terminal-a-shell-a-tty-and-a-con)
那我们在这里只给出一般的形象性解释:terminal和console一般是直接连接的物理设备;shell,我们经常提起command-line shell,是一种special program,提供launch other programs的功能,想想刚开始的时候那张shell和系统调用的关系图;tty,这个词的缩写挺有历史了,teletypewriter,可以看成一种特殊的设备文件,tty file,去“/dev”下面看看,有很多。或者啊,你把它当成terminal的近义词也成;关键是tty1~tty6,按下ctrl+alt+F1~F6,有六套virtual terminals,它们公用一套物理设备,切换到哪一个那么/dev/tty就代表哪一个。OK,言尽如此,自己体会,下面看terminal logins和network logins,也就是终端登录和网络登录。
终端登录:怎么登录呢?分三步走,init、getty和login。(http://akaedu.github.io/book/ch34s01.html)
(1)系统启动时创建init进程(ID=1),调用fork,fork出的子进程exec getty;(记得吗,exec不会改变进程ID)
(2)getty open terminal devices,将0 1 2指向控制终端,输出“login: ”类似的东西,等待用户输入账号;(想想非图形界面的登录)
(3)用户输入账号后,调login,提示“password:”类似的东西,登录失败则回到第一步重新fork;成功则设置环境后进入shell。
注意,init fork之后的3个进程ID相同,因为exec不改变进程ID嘛!
网络登录:首先,听过pseudo tty吗?这是伪终端,也是个tty,那我们通过下面的图简单讲一下网络登录的过程。
现在是网络了啊,不只有6个虚拟终端了,很多很多啦。来看步骤:
(1)首先用户通过telnet服务进程连接服务器。服务器那边有一个inetd(Internet super-server)专门接请求,接到一个请求它就fork一个子进程来exec telnetd服务器,然后inetd接着等待接其它请求;
(2)telnetd服务器打开一个伪终端,然后fork:父进程操作伪终端的主设备(pty master),子进程操纵从设备(pty slave, 准确的说是从设备的控制终端,包括指向fd 0 1 2),这下子,父子协同上阵了;
(3)telnetd服务器接到一个东西后,看箭头,转了整整一大圈再送回去,为什么要绕那么一大圈呢?我们看啊,在功能概念上,主设备类似于键盘和显示器,从设备类似于/dev/tty,这样从设备可以当成我从键盘上接受数据,最后再送回显示器上,他才不管真正的用户是谁呢,这是不是设计的很棒啊~
Sessions & job control(会话和作业控制)
我们把这两个东西混着说,因为它们的联系很紧密。首先,session是一个或多个进程组的集合(它和通信中的session有啥关系我还没搞清楚)。
看这个session包含三个process group。首先,如果一个会话有一个controlling terminal,那么他就有一个前台进程组和若干个后台进程组。下面,我们从session和process group的角度来看登录和执行命令的过程:
(1)想想刚开始登录的时候,getty(终端登录)或telnetd(网络登录)要打开终端设备,指定fd,那么打开终端设备之前,调setsid创建new session,这个新建session的进程就是session leader,它所创建的进程组叫process group leader;
(2)假如shell fork出proc345,然后指定proc3是leader;由于只能一个前台,所以如果想要这个进程组在前台运行,那么shell必须要转到后台并wait,直到proc345都结束,再把自己提到前台去;那么假如proc3在运行期间又fork出一个子进程一直运行着,还没结束怎么办?当然是被init收养啦,还记得吧~
note:无论何时我们按下ctrl+c等信号,都会发送到前台的所有进程中。
那么,什么又是作业呢?proc3 | proc4 | proc5是shell的作业,但proc3 fork出的子进程不属于作业,但属于同一个进程组,这就是区别。
好啦,不多不少,刚刚好,就讲那么多,明天看第十章,信号~