1
+ #include "unp.h"
2
+
3
+ void sig_chld (int signo ) {
4
+ pid_t pid ;
5
+ int stat ;
6
+
7
+ // #include <sys/types.h>
8
+ // #include <sys/wait.h>
9
+
10
+ // pid_t wait(int *status);
11
+ // param: pid = -1的时候表示等待第一个终止的子进程, options参数中指定WNOHANG可以使父进程不阻塞而立即返回0
12
+ // pid_t waitpid(pid_t pid, int *status, int options);
13
+
14
+ // 两个函数成功均返回进程pid 出错则返回0或-1
15
+
16
+ // 1. 若调用成功则返回清理掉的子进程id,若调用出错则返回-1。父进程调用wait或waitpid时可能会:
17
+ // 1. 阻塞(如果它的所有子进程都还在运行)。
18
+ // 2. 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。
19
+ // 3. 出错立即返回(如果它没有任何子进程)。
20
+ // 2. 这两个函数的区别是:
21
+ // 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。
22
+ // wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。
23
+ // 可见,调用wait和waitpid不仅可以获得子进程的终止信息,还可以使父进程阻塞等待子进程终止,起到进程间同步的作用。如果参数status不是空指针,则子进程的终止信息通过这个参数传出,如果只是为了同步而不关心子进程的终止信息,可以将status参数指定为NULL。
24
+
25
+ // 为什么不用wait而用waitpid?
26
+ // 1. 建立一个信号处理函数并在信号处理函数中调用wait并不能防止出现僵尸进程
27
+ // 2. 如果多个链接在同一时间退出所有的多个信号在处理函数之前产生而信号函数只执行一次(理想应该执行多次)
28
+ // 3. 因为unix对信号一般是不排队的,因此使用waitpid循环等待获取所有终止进程的信息,如果没有子进程已经终止时就不阻塞退出,如果有多个线程终止就循环捕获。
29
+ // 4. wait函数只会阻塞等待子进程 如果有还在运行的进程也会阻塞等待。
30
+ while ((pid = waitpid (-1 , & stat , WNOHANG )) > 0 ) {
31
+ printf ("child %d terminated" , pid );
32
+ }
33
+ return ;
34
+ }
35
+
36
+
37
+ int main (int argc , char * * argv ) {
38
+ int listenfd , connfd ;
39
+ pid_t childpid ;
40
+ socklen_t clilen ;
41
+ struct sockaddr_in servaddr , cliaddr ;
42
+
43
+ bzero (& servaddr , sizeof (servaddr ));
44
+ servaddr .sin_family = AF_INET ;
45
+ servaddr .sin_port = htons (SERV_PORT );
46
+ servaddr .sin_addr .s_addr = htonl (INADDR_ANY );
47
+
48
+ if ((listenfd = socket (AF_INET , SOCK_STREAM , 0 )) < 0 ) {
49
+ err_sys ("socket error" );
50
+ }
51
+
52
+ if (bind (listenfd , (struct sockaddr * )& servaddr , sizeof (servaddr )) < 0 ) {
53
+ err_sys ("bind error" );
54
+ }
55
+
56
+ if (listen (listenfd , LISTENQ ) < 0 ) {
57
+ err_sys ("listen error" );
58
+ }
59
+
60
+ Singal (SIGCHLD , sig_chld );
61
+
62
+ for (;;) {
63
+ clilen = sizeof (cliaddr );
64
+ if ((connfd = accept (listenfd , (SA * )& cliaddr , & clilen )) < 0 ) {
65
+ if (errno == EINTR ) {
66
+ continue ;
67
+ } else {
68
+ err_sys ("accept error" );
69
+ }
70
+ }
71
+ if ((childpid = Fork ()) == 0 ) {
72
+ Close (listenfd );
73
+ str_echo (connfd );
74
+ exit (0 );
75
+ }
76
+ Close (connfd );
77
+ }
78
+ }
0 commit comments