《TCP/IP网络编程》第 10 章 多进程服务器端 笔记( 六 )


编译运行:
gcc sigaction.c -o sigaction./sigaction
结果:
wait...Time out!wait...Time out!wait...Time out!
可以发现,结果和之前用函数的结果没有什么区别 。以上就是信号处理的相关理论 。
10.3.4 利用信号处理技术消灭僵尸进程
下面利用子进程终止时产生信号这一点,来用信号处理来消灭僵尸进程 。看以下代码:
#include #include #include #include #include void read_childproc(int sig){int status;pid_t id = waitpid(-1, &status, WNOHANG);if (WIFEXITED(status)){printf("Removed proc id: %d \n", id);//子进程的 pidprintf("Child send: %d \n", WEXITSTATUS(status)); //子进程的返回值}}int main(int argc, char *argv[]){pid_t pid;struct sigaction act;act.sa_handler = read_childproc;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGCHLD, &act, 0);pid = fork();if (pid == 0) //子进程执行阶段{puts("Hi I'm child process");sleep(10);return 12;}else //父进程执行阶段{printf("Child proc id: %d\n", pid);pid = fork();if (pid == 0){puts("Hi! I'm child process");sleep(10);exit(24);}else{int i;printf("Child proc id: %d \n", pid);for (i = 0; i < 5; i++){puts("wait");sleep(5);}}}return 0;}
编译运行:
gcc remove_zomebie.c -o zombie./zombie
结果:
Child proc id: 11211Hi I'm child processChild proc id: 11212 waitHi! I'm child processwaitwaitRemoved proc id: 11211 Child send: 12 waitRemoved proc id: 11212 Child send: 24 wait
请自习观察结果,结果中的每一个空行代表间隔了5 秒,程序是先创建了两个子进程,然后子进程 10 秒之后会返回值,第一个 wait 由于子进程在执行,所以直接被唤醒,然后这两个子进程正在睡 10 秒,所以 5 秒之后第二个 wait 开始执行,又过了 5 秒,两个子进程同时被唤醒 。所以剩下的 wait 也被唤醒 。
所以在本程序的过程中,当子进程终止时候,会向系统发送一个信号,然后调用我们提前写好的处理函数,在处理函数中使用来处理僵尸进程,获取子进程返回值 。
10.4 基于多任务的并发服务器 10.4.1 基于进程的并发服务器模型
之前的回声服务器每次只能同事向 1 个客户端提供服务 。因此,需要扩展回声服务器,使其可以同时向多个客户端提供服务 。下图是基于多进程的回声服务器的模型 。
从图中可以看出,每当有客户端请求时(连接请求),回声服务器都创建子进程以提供服务 。如果请求的客户端有 5 个,则将创建 5 个子进程来提供服务,为了完成这些任务,需要经过如下过程:
10.4.2 实现并发服务器
下面是基于多进程实现的并发的回声服务器的服务端,可以结合第四章的 .c 回声客户端来运行 。
编译运行:
gcc echo_mpserv.c -o eserver./eserver
结果:
和第四章的几乎一样,可以自己测试,此时的服务端支持同时给多个客户端进行服务,每有一个客户端连接服务端,就会多开一个子进程,所以可以同时提供服务 。
10.4.3 通过 fork 函数复制文件描述符
示例中给出了通过 fork 函数复制文件描述符的过程 。父进程将 2 个套接字(一个是服务端套接字另一个是客户端套接字)文件描述符复制给了子进程 。
调用 fork 函数时赋值父进程的所有资源,但是套接字不是归进程所有的,而是归操作系统所有,只是进程拥有代表相应套接字的文件描述符 。

《TCP/IP网络编程》第 10 章 多进程服务器端 笔记