【unix网络编程】含信号处理服务器程序

SIGCHID信号

待解决的问题

  1. 当子进程结束时,会给父进程发送一个SIGCHID信号,而我们之前的服务器程序默认是不处理的。此时子进程就会是半死不死的僵死程序,会占用系统进程资源。因此我们需要建立一个信号处理程序,每当发生这个SIGCHID信号时,都对其进行处理,消灭它。
  2. 系统自带的有wait和waitpid程序可以处理上述问题,但是两者有区别。前者可能不能处理多子进程同时结束的情况
  3. 信号处理函数返回时,如果是慢系统可能会返回一个EINT错误,如何对其进行处理。

信号处理函数

POSIX规定
1. 信号处理函数安装(存在并且调用)一次,就一直安装着。(类似中断处理),因此在子进程创建之前建立就可以了。
2. 信号处理函数运行时,正在递交的信号全部被阻塞,同时可以阻塞其他信号(sigaction函数中的sa_mask,空集则表示不阻塞其他信号。)

wait和waitpid

wait函数比较简单,是后者的特殊情况。
进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
因此,如果放在while循环里面,那么一旦存在正在运行的子进程就会一直阻塞,导致无法退出信号处理函数。
后者可以指定选项参数,要求不阻塞就可以。

#include    "unp.h"

int
main(int argc, char **argv)
{
    int                 listenfd, connfd;
    pid_t               childpid;
    socklen_t           clilen;
    struct sockaddr_in  cliaddr, servaddr;
    void                sig_chld(int);

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(SERV_PORT);

    Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

    Listen(listenfd, LISTENQ);
    //新增的部分
    Signal(SIGCHLD, sig_chld);  /* must call waitpid() */

    for ( ; ; ) {
        clilen = sizeof(cliaddr);
        //新增的部分
        if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0) {
            if (errno == EINTR)
                continue;       /* back to for() */
            else
                err_sys("accept error");
        }

        if ( (childpid = Fork()) == 0) {    /* child process */
            Close(listenfd);    /* close listening socket */
            str_echo(connfd);   /* process the request */
            exit(0);
        }
        Close(connfd);          /* parent closes connected socket */
    }
}

SIGPIPE信号

待解决的问题

1.当一个进程想某个已经收到RST的套接字执行写操作时,内核会向进程发送一个SIGPIPE信号。
如果不处理,则客户端进程难以知道是由于连接已经断开,而是认识是异常终止。与实际不符合。

处理方式

将写操作分两步,第一步引发RST,然后再写剩余的东西,可以收到一个SIGPIPE信号。
如果不想终止进程可以忽略。

struct sigaction act;
act.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &act, NULL) == 0) 
{
    LOG("SIGPIPE ignore");
}

猜你喜欢

转载自blog.csdn.net/wushuomin/article/details/80647870