boa阅读笔记3

本文详细介绍了程序启动初期的日志配置过程,包括错误日志、权限日志和CGI日志的打开与重定向,以及如何设置日志文件在执行exec时不被新建进程继承。此外,还介绍了监听socket的创建流程,包括设置socket为非阻塞模式、设置地址复用选项等。
void open_logs(void)
{
    int error_log;

    /* if error_log_name is set, dup2 stderr to it */
    /* otherwise, leave stderr alone */
    /* we don't want to tie stderr to /dev/null */
    if (error_log_name) {
        /* open the log file */
        if (!(error_log = open_gen_fd(error_log_name))) {
            DIE("unable to open error log");
        }

        /* redirect stderr to error_log */
        if (dup2(error_log, STDERR_FILENO) == -1) {
            DIE("unable to dup2 the error log");
        }
        close(error_log);
    }

    /* set the close-on-exec to true */
    //当使用exec时关闭stderr,防止其他程序写stderr
    if (fcntl(STDERR_FILENO, F_SETFD, 1) == -1) {
        DIE("unable to fcntl the error log");
    }

    if (access_log_name) {//权限日志
        /* Used the "a" flag with fopen, but fopen_gen_fd builds that in
         * implicitly when used as a file, and "a" is incompatible with
         * pipes and network sockets. */
        if (!(access_log = fopen_gen_fd(access_log_name, "w"))) {
            int errno_save = errno;
            fprintf(stderr, "Cannot open %s for logging: ",
                    access_log_name);
            errno = errno_save;
            perror("logfile open");
            exit(errno);
        }
        /* line buffer the access log */
#ifdef SETVBUF_REVERSED
        setvbuf(access_log, _IOLBF, (char *) NULL, 0);
#else
        setvbuf(access_log, (char *) NULL, _IOLBF, 0);
#endif
    } else
        access_log = NULL;

    if (cgi_log_name) {//cgi日志
        cgi_log_fd = open_gen_fd(cgi_log_name);
        if (cgi_log_fd == -1) {
            WARN("open cgi_log");
            free(cgi_log_name);
            cgi_log_name = NULL;
            cgi_log_fd = 0;
        } else {
            if (fcntl(cgi_log_fd, F_SETFD, 1) == -1) {//当exec时关闭cgi_log
                WARN("unable to set close-on-exec flag for cgi_log");
                close(cgi_log_fd);
                cgi_log_fd = 0;
                free(cgi_log_name);
                cgi_log_name = NULL;
            }
        }
    }
}

open_logs完成了程序所需日志的打开、重定向和设置,并防止新建进程对日志的干扰。

完成 一系列的环境初始化后,接下来就是创建监听socket了。

    server_s = create_server_socket();

static int create_server_socket(void)
{
    int server_s;
    
    server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP); //创建TCP协议的socket
    if (server_s == -1) {
        DIE("unable to create socket");
    }

    /* server socket is nonblocking */
    if (set_nonblock_fd(server_s) == -1) {//设置文件描述符为无阻塞模式
        DIE("fcntl: unable to set server socket to nonblocking");
    }

    /* close server socket on exec so cgi's can't write to it */
    if (fcntl(server_s, F_SETFD, 1) == -1) {      //FD_CLOEXEC
        DIE("can't set close-on-exec on server socket!");
    }

    /* reuse socket addr */
    if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
                    sizeof (sock_opt))) == -1) {
        DIE("setsockopt");
    }

    /* internet family-specific code encapsulated in bind_server()  */
    if (bind_server(server_s, server_ip) == -1) {//实现了ipv4和ipv6的定制绑定
        DIE("unable to bind");
    }

    /* listen: large number just in case your kernel is nicely tweaked */
    if (listen(server_s, backlog) == -1) {//监听
        DIE("unable to listen");
    }
    return server_s;
}

一个标准的socket创建流程后,服务端口已经成功被程序监听。

接下来是对信号处理函数进行设置。

    init_signals();
void init_signals(void)
{
    struct sigaction sa;

    sa.sa_flags = 0;
    //设置在信号处理函数中需要屏蔽的信号
    sigemptyset(&sa.sa_mask); //清空sa_mask
    sigaddset(&sa.sa_mask, SIGSEGV);
    sigaddset(&sa.sa_mask, SIGBUS);
    sigaddset(&sa.sa_mask, SIGTERM);
    sigaddset(&sa.sa_mask, SIGHUP);
    sigaddset(&sa.sa_mask, SIGINT);
    sigaddset(&sa.sa_mask, SIGPIPE);
    sigaddset(&sa.sa_mask, SIGCHLD);
    sigaddset(&sa.sa_mask, SIGALRM);
    sigaddset(&sa.sa_mask, SIGUSR1);
    sigaddset(&sa.sa_mask, SIGUSR2);
    //设置信号处理函数
    sa.sa_handler = sigsegv;
    sigaction(SIGSEGV, &sa, NULL);

    sa.sa_handler = sigbus;
    sigaction(SIGBUS, &sa, NULL);

    sa.sa_handler = sigterm;
    sigaction(SIGTERM, &sa, NULL);

    sa.sa_handler = sighup;
    sigaction(SIGHUP, &sa, NULL);

    sa.sa_handler = sigint;
    sigaction(SIGINT, &sa, NULL);

    sa.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &sa, NULL);

    sa.sa_handler = sigchld;
    sigaction(SIGCHLD, &sa, NULL);

    sa.sa_handler = sigalrm;
    sigaction(SIGALRM, &sa, NULL);

    sa.sa_handler = SIG_IGN;
    sigaction(SIGUSR1, &sa, NULL);

    sa.sa_handler = SIG_IGN;
    sigaction(SIGUSR2, &sa, NULL);
}

完成了信号的设置,离程序真正开始工作又近了一步,下次再接着分析下面几步。


转载于:https://my.oschina.net/firemiles/blog/324051

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值