mirror of
https://github.com/riba2534/TCP-IP-NetworkNote.git
synced 2026-02-03 18:13:22 +08:00
修改 ch10 错别字
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
|
||||
#### 10.1.3 进程 ID
|
||||
|
||||
在说进程创建方法之前,先要简要说明进程 ID。无论进程是如何创建的,所有的进程都会被操作系统分配一个 ID。此 ID 被称为「进程ID」,其值为大于 2 的证书。1 要分配给操作系统启动后的(用于协助操作系统)首个进程,因此用户无法得到 ID 值为 1 。接下来观察在 Linux 中运行的进程。
|
||||
在说进程创建方法之前,先要简要说明进程 ID。无论进程是如何创建的,所有的进程都会被操作系统分配一个 ID。此 ID 被称为「进程ID」,其值为大于 2 的整数。1 要分配给操作系统启动后的(用于协助操作系统)首个进程,因此用户无法得到 ID 值为 1 。接下来观察在 Linux 中运行的进程。
|
||||
|
||||
```shell
|
||||
ps au
|
||||
@@ -123,9 +123,9 @@ gcc fork.c -o fork
|
||||
- 传递参数并调用 exit() 函数
|
||||
- main 函数中执行 return 语句并返回值
|
||||
|
||||
**向 exit 函数传递的参数值和 main 函数的 return 语句返回的值都回传递给操作系统。而操作系统不会销毁子进程,直到把这些值传递给产生该子进程的父进程。处在这种状态下的进程就是僵尸进程。**也就是说将子进程变成僵尸进程的正是操作系统。既然如此,僵尸进程何时被销毁呢?
|
||||
**向 exit 函数传递的参数值和 main 函数的 return 语句返回的值都会传递给操作系统。而操作系统不会销毁子进程,直到把这些值传递给产生该子进程的父进程。处在这种状态下的进程就是僵尸进程。**也就是说将子进程变成僵尸进程的正是操作系统。既然如此,僵尸进程何时被销毁呢?
|
||||
|
||||
> 应该向创建子进程册父进程传递子进程的 exit 参数值或 return 语句的返回值。
|
||||
> 应该向创建子进程的父进程传递子进程的 exit 参数值或 return 语句的返回值。
|
||||
|
||||
如何向父进程传递这些值呢?操作系统不会主动把这些值传递给父进程。只有父进程主动发起请求(函数调用)的时候,操作系统才会传递该值。换言之,如果父进程未主动要求获得子进程结束状态值,操作系统将一直保存,并让子进程长时间处于僵尸进程状态。也就是说,父母要负责收回自己生的孩子。接下来的示例是创建僵尸进程:
|
||||
|
||||
@@ -327,7 +327,7 @@ gcc waitpid.c -o waitpid
|
||||
|
||||
#### 10.3.1 向操作系统求助
|
||||
|
||||
子进程终止的识别主题是操作系统,因此,若操作系统能把如下信息告诉正忙于工作的父进程,将有助于构建更高效的程序
|
||||
子进程终止的识别主题是操作系统,因此,若操作系统能把子进程结束的信息告诉正忙于工作的父进程,将有助于构建更高效的程序
|
||||
|
||||
为了实现上述的功能,引入信号处理机制(Signal Handing)。此处「信号」是在特定事件发生时由操作系统向进程发送的消息。另外,为了响应该消息,执行与消息相关的自定义操作的过程被称为「处理」或「信号处理」。
|
||||
|
||||
@@ -337,7 +337,7 @@ gcc waitpid.c -o waitpid
|
||||
|
||||
> 进程:操作系统,如果我之前创建的子进程终止,就帮我调用 zombie_handler 函数。
|
||||
>
|
||||
> 操作系统:好的,如果你的子进程终止,我舅帮你调用 zombie_handler 函数,你先把要函数要执行的语句写好。
|
||||
> 操作系统:好的,如果你的子进程终止,我就帮你调用 zombie_handler 函数,你先把函数要执行的语句写好。
|
||||
|
||||
上述的对话,相当于「注册信号」的过程。即进程发现自己的子进程结束时,请求操作系统调用的特定函数。该请求可以通过如下函数调用完成:
|
||||
|
||||
@@ -362,7 +362,7 @@ void (*signal(int signo, void (*func)(int)))(int);
|
||||
|
||||
> 「子进程终止则调用 mychild 函数」
|
||||
|
||||
此时 mychild 函数的参数应为 int ,返回值类型应为 void 。只有这样才能称为 signal 函数的第二个参数。另外,常数 SIGCHLD 定义了子进程终止的情况,应成为 signal 函数的第一个参数。也就是说,signal 函数调用语句如下:
|
||||
此时 mychild 函数的参数应为 int ,返回值类型应为 void 。只有这样才能成为 signal 函数的第二个参数。另外,常数 SIGCHLD 定义了子进程终止的情况,应成为 signal 函数的第一个参数。也就是说,signal 函数调用语句如下:
|
||||
|
||||
```c
|
||||
signal(SIGCHLD , mychild);
|
||||
@@ -442,7 +442,7 @@ gcc signal.c -o signal
|
||||
|
||||
> 发生信号时将唤醒由于调用 sleep 函数而进入阻塞状态的进程。
|
||||
|
||||
调用函数的主题的确是操作系统,但是进程处于睡眠状态时无法调用函数,因此,产生信号时,为了调用信号处理器,将唤醒由于调用 sleep 函数而进入阻塞状态的进程。而且,进程一旦被唤醒,就不会再进入睡眠状态。即使还未到 sleep 中规定的时间也是如此。所以上述示例运行不到 10 秒后就会结束,连续输入 CTRL+C 可能连一秒都不到。
|
||||
调用函数的主体的确是操作系统,但是进程处于睡眠状态时无法调用函数,因此,产生信号时,为了调用信号处理器,将唤醒由于调用 sleep 函数而进入阻塞状态的进程。而且,进程一旦被唤醒,就不会再进入睡眠状态。即使还未到 sleep 中规定的时间也是如此。所以上述示例运行不到 10 秒后就会结束,连续输入 CTRL+C 可能连一秒都不到。
|
||||
|
||||
**简言之,就是本来系统要睡眠100秒,但是到了 alarm(2) 规定的两秒之后,就会唤醒睡眠的进程,进程被唤醒了就不会再进入睡眠状态了,所以就不用等待100秒。如果把 timeout() 函数中的 alarm(2) 注释掉,就会先输出`wait...`,然后再输出`Time out!` (这时已经跳过了第一次的 sleep(100) 秒),然后就真的会睡眠100秒,因为没有再发出 alarm(2) 的信号。**
|
||||
|
||||
@@ -499,7 +499,7 @@ int main(int argc, char *argv[])
|
||||
int i;
|
||||
struct sigaction act;
|
||||
act.sa_handler = timeout; //保存函数指针
|
||||
sigemptyset(&act.sa_mask); //将 sa_mask 函数的所有位初始化成0
|
||||
sigemptyset(&act.sa_mask); //将 sa_mask 成员的所有位初始化成0
|
||||
act.sa_flags = 0; //sa_flags 同样初始化成 0
|
||||
sigaction(SIGALRM, &act, 0); //注册 SIGALRM 信号的处理器。
|
||||
|
||||
@@ -670,7 +670,7 @@ gcc echo_mpserv.c -o eserver
|
||||
|
||||

|
||||
|
||||
如图所示,1 个套接字存在 2 个文件描述符时,只有 2 个文件描述符都终止(销毁)后,才能销毁套接字。如果维持图中的状态,即使子进程销毁了与客户端连接的套接字文件描述符,也无法销毁套接字(服务器套接字同样如此)。因此调用 fork 函数候,要将无关紧要的套接字文件描述符关掉,如图所示:
|
||||
如图所示,1 个套接字存在 2 个文件描述符时,只有 2 个文件描述符都终止(销毁)后,才能销毁套接字。如果维持图中的状态,即使子进程销毁了与客户端连接的套接字文件描述符,也无法销毁套接字(服务器套接字同样如此)。因此调用 fork 函数后,要将无关紧要的套接字文件描述符关掉,如图所示:
|
||||
|
||||

|
||||
|
||||
@@ -688,13 +688,13 @@ gcc echo_mpserv.c -o eserver
|
||||
|
||||
从图中可以看出,客户端的父进程负责接收数据,额外创建的子进程负责发送数据,分割后,不同进程分别负责输入输出,这样,无论客户端是否从服务器端接收完数据都可以进程传输。
|
||||
|
||||
分割 I/O 程序的另外一个好处是,可以提高频繁交换数据的程序性能,图下图所示:
|
||||
分割 I/O 程序的另外一个好处是,可以提高频繁交换数据的程序性能,如下图所示:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
根据上图显示可以看出,再网络不好的情况下,明显提升速度。
|
||||
根据上图显示可以看出,在网络不好的情况下,明显提升速度。
|
||||
|
||||
#### 10.5.2 回声客户端的 I/O 程序分割
|
||||
|
||||
|
||||
Reference in New Issue
Block a user