UNP第五章总结
1.处理信号SIGCHLD
当服务器子进程退出时会向父进程传递SIGCHLD信号。如果不处理该信号将僵死的子进程回收,则太多的僵死进程会占用过多系统资源。
wait和waitpid
wait函数会阻塞回收僵死进程,如果没有子进程退出将一直等待
waitpid函数可以设置WNOHANG将其设置为非阻塞的。
void
sig_chld(int signo)
{
pid_t pid;
int stat;
//wait(&stat);
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
- wait的缺点:由于调用信号处理函数时,相同的信号会被阻塞。如果在信号处理函数调用时又有多个子进程退出,而wait只调用一次无法回收多个子进程。当信号处理函数调用完成时SIGCHLD信号只会被再处理一次。且由于wait是阻塞的我们不能使用while循环来调用wait进行多个子进程的回收。
- waitpid:waitpid可以是非阻塞的,因此可以在信号处理函数中使用while循环调用waitpid函数,实现一次调用回收多个的效果。
2. 正确处理被信号中断的系统调用
for ( ; ; ) {
clilen = sizeof(cliaddr);
//accept(listenfd, (SA*)&cliaddr, &clilen);
if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0) {
if (errno == EINTR)
continue;
else
err_sys("accept error");
}
if ( (childpid = Fork()) == 0) {
Close(listenfd);
str_echo(connfd);
exit(0);
}
Close(connfd);
}
当父进程阻塞在accept上时,如果被SIGCHLD信号中断,并终止。因此需要对返回的错误进行处理。
当编写信号处理函数时需要正确认识被中断的系统调用并处理他们
3. 服务器进程退出
- 服务器进程退出时会向客户端发送FIN
- 如果客户端向已关闭的服务器端发送数据则服务器端会返回RST
- 客户端继续向收到RST的socket写数据会触发SIGPIPE信号并返回EPIPE错误
4. 服务器崩溃
- 服务器崩溃即从网络上消失,不发送FIN
- 此时客户端并不知情,客户端向服务器端多次发送数据未收到ACK后会返回ETIMEOUT
- 想要在未发生数据前就检测出服务器端崩溃使用SO_KEEPALIVE套接字选项