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); }
完成了信号的设置,离程序真正开始工作又近了一步,下次再接着分析下面几步。