码迷,mamicode.com
首页 > 系统相关 > 详细

TCP/IP 网络编程 (抄书笔记 3) -- 僵尸进程和多任务并发服务器

时间:2015-09-26 00:32:30      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:

TCP/IP 网络编程 (抄书笔记 3) – 僵尸进程和多任务并发服务器

TCP/IP 网络编程 (抄书笔记 3) – 僵尸进程和多任务并发服务器

僵尸进程的产生

  1. 子进程先退出, 父进程没有退出 ==> 僵尸进程
  2. 父进程先退出, 子进程没有退出 ==> 子进程被 0 号进程回收, 不会产生僵尸进程
pid_t pid = fork();
if (pid == 0) {  // child
    printf("child: %d\n", getpid());
    printf("child exited\n");
    exit(0);
} else {
    printf("parent: %d\n", getpid());
    sleep(30);
}

避免僵尸进程

子进程退出的时候, 通知父进程:
父进程调用

int status;
wait(&status);
WIFEXITED(status);
WEXITSTATUS(status);

这样就可以等待子进程的退出, 并获取他的返回值
如果父进程先调用了 exit 等命令自己退出, 那么子进程会被 0 号进程回收

调用 wait 的话, 父进程会阻塞自己, 直到子进程退出, 如果不想阻塞可以使用

waitpid(-1, &status, WNOHANG);

信号

void keyboard(int sig) {
        if (sig == SIGINT) {
                printf("Ctrl + C pressed\n");
        }
}

void timeout(int sig) {
        if (sig == SIGALRM) {
                printf("time out ...\n");
                exit(0);
        }
}

int main() {
    ...

    signal(SIGINT, keyboard);
    signal(SIGALRM, timeout);
    alarm(3);               // 时间结束, 会产生一个信号, 然后自动调用 timeoutu 函数

    ...
}

使用 sigaction, signal 过时

struct sigaction act;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
act.sa_handler = timeout;
sigaction(SIGALRM, &act, 0);

利用信号消灭僵尸进程
原理: 只要做到子进程退出的时候告诉父进程一声, "我要退出了" 就可以消灭僵尸进程, 也就是调用 wait/waitpid, 子进程退出的信号是 SIGCHLD

多任务的并发服务器

void read_childproc(int sig) {
        int status;
        if (sig == SIGCHLD) {
                if (WIFEXITED(status)) {
                        printf("child quit ... %d\n", WEXITSTATUS(status));
                }
        }
}

int main(int argc, char *argv[]) {
        int server_sock;
        int client_sock;

        struct sockaddr_in server_addr;
        struct sockaddr_in client_addr;

        // socket
        server_sock = socket(AF_INET, SOCK_STREAM, 0);

        // bind
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        server_addr.sin_port = htons(atoi(argv[1]));
        bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));

        // listen
        listen(server_sock, 5);

        // sigaction
        struct sigaction act;
        act.sa_handler = read_childproc;


        char buf[BUF_SIZE];
        int str_len;

        pid_t pid;

        while (1) {
                socklen_t client_size = sizeof(client_addr);
                client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_size);

                pid = fork();
                if (pid == 0) { // 子进程复制, 这时候打开了 4 个 fd, 需要子进程关一个, 父进程关一个, 看下图
                        close(server_sock);
                        while ((str_len = read(client_sock, buf, BUF_SIZE)) != 0) {
                                write(client_sock, buf, str_len);
                        }

                        close(server_sock);
                        printf("client disconnected ...\n");
                } else {        // 父进程将 client 交给子进程处理, 自己继续监听 server fd
                        close(client_sock);
                }
        }

        close(server_sock);
        close(client_sock);

        return 0;
}

技术分享

TCP/IP 网络编程 (抄书笔记 3) -- 僵尸进程和多任务并发服务器

标签:

原文地址:http://www.cnblogs.com/sunznx/p/4839811.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!