[user@localhost HomeWork_makefile2]$ make
gcc -Wall -Wextra -std=c99 -o process_server multi_process.c
multi_process.c:54:1: error: stray ‘\346’ in program
 void send_http_response(int client_f极, http_status_t status, 
 ^
multi_process.c:54:1: error: stray ‘\236’ in program
multi_process.c:54:1: error: stray ‘\201’ in program
multi_process.c: In function ‘send_http_response’:
multi_process.c:74:10: error: ‘client_fd’ undeclared (first use in this function)
     send(client_fd, header, len, 0);
          ^
multi_process.c:74:10: note: each undeclared identifier is reported only once for each function it appears in
multi_process.c:54:29: warning: unused parameter ‘client_f’ [-Wunused-parameter]
 void send_http_response(int client_f极, http_status_t status, 
                             ^
multi_process.c: In function ‘send_error_response’:
multi_process.c:80:5: warning: enumeration value ‘HTTP_200’ not handled in switch [-Wswitch]
     switch (status) {
     ^
multi_process.c: In function ‘main’:
multi_process.c:173:22: error: storage size of ‘sa’ isn’t known
     struct sigaction sa;
                      ^
multi_process.c:175:5: warning: implicit declaration of function ‘sigemptyset’ [-Wimplicit-function-declaration]
     sigemptyset(&sa.sa_mask);
     ^
multi_process.c:176:19: error: ‘SA_RESTART’ undeclared (first use in this function)
     sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
                   ^
multi_process.c:176:32: error: ‘SA_NOCLDSTOP’ undeclared (first use in this function)
     sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
                                ^
multi_process.c:178:5: warning: implicit declaration of function ‘sigaction’ [-Wimplicit-function-declaration]
     if (sigaction(SIGCHLD, &sa, NULL) == -1) {
     ^
multi_process.c:173:22: warning: unused variable ‘sa’ [-Wunused-variable]
     struct sigaction sa;
                      ^
makefile:17: recipe for target 'process_server' failed
make: *** [process_server] Error 1  报错如上,代码如下#include "web_server.h"
// 创建socket
int create_socket() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    
    int opt = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    return sockfd;
}
// 绑定socket
void bind_socket(int sockfd) {
    struct sockaddr_in server_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(PORT),
        .sin_addr.s_addr = INADDR_ANY
    };
    
    if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
}
// 获取内容类型
const char* get_content_type(const char* path) {
    const char* ext = strrchr(path, '.');
    if (!ext) return "text/plain";
    ext++;
    
    if (strcmp(ext, "html") == 0) return "text/html";
    if (strcmp(ext, "css") == 0) return "text/css";
    if (strcmp(ext, "js") == 0) return "application/javascript";
    if (strcmp(ext, "jpg") == 0) return "image/jpeg";
    if (strcmp(ext, "png") == 0) return "image/png";
    if (strcmp(ext, "gif") == 0) return "image/gif";
    if (strcmp(ext, "json") == 0) return "application/json";
    
    return "text/plain";
}
// 检查路径安全性
int is_path_safe(const char* path) {
    return strstr(path, "..") == NULL;
}
// 发送HTTP响应
void send_http_response(int client_f极, http_status_t status, 
                        const char* content_type, off_t content_length) {
    const char* status_msg = "";
    switch (status) {
        case HTTP_200: status_msg = "OK"; break;
        case HTTP_400: status_msg = "Bad Request"; break;
        case HTTP_403: status_msg = "Forbidden"; break;
        case HTTP_404: status_msg = "Not Found"; break;
        case HTTP_500: status_msg = "Internal Server Error"; break;
        case HTTP_501: status_msg = "Not Implemented"; break;
    }
    
    char header[512];
    int len = snprintf(header, sizeof(header),
        "HTTP/1.1 %d %s\r\n"
        "Content-Type: %s\r\n"
        "Content-Length: %ld\r\n"
        "Connection: close\r\n\r\n",
        status, status_msg, content_type, content_length);
    
    send(client_fd, header, len, 0);
}
// 发送错误响应
void send_error_response(int client_fd, http_status_t status) {
    const char* body = "";
    switch (status) {
        case HTTP_400: body = "<h1>400 Bad Request</h1>"; break;
        case HTTP_403: body = "<h1>403 Forbidden</h1>"; break;
        case HTTP_404: body = "<h1>404 Not Found</h1>"; break;
        case HTTP_500: body = "<h1>500 Internal Server Error</h1>"; break;
        case HTTP_501: body = "<h1>501 Not Implemented</h1>"; break;
    }
    
    char response[512];
    int len = snprintf(response, sizeof(response),
        "HTTP/1.1 %d %s\r\n"
        "Content-Type: text/html\r\n"
        "Content-Length: %zu\r\n"
        "Connection: close\r\n\r\n%s",
        status, 
        (status == 400) ? "Bad Request" : 
        (status == 403) ? "Forbidden" :
        (status == 404) ? "Not Found" : 
        (status == 500) ? "Internal Server Error" : "Not Implemented",
        strlen(body), body);
    
    send(client_fd, response, len, 0);
}
// SIGCHLD信号处理器
void sigchld_handler(int sig) {
    (void)sig;
    while (waitpid(-1, NULL, WNOHANG) > 0);
}
// 处理客户端请求
void process_request(int client_fd) {
    char buffer[MAX_REQUEST_SIZE];
    ssize_t bytes_read = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
    
    if (bytes_read <= 0) {
        close(client_fd);
        exit(EXIT_FAILURE);
    }
    
    buffer[bytes_read] = '\0';
    
    char method[16], path[256], protocol[16];
    if (sscanf(buffer, "%15s %255s %15s", method, path, protocol) != 3) {
        send_error_response(client_fd, HTTP_400);
        close(client_fd);
        exit(EXIT_FAILURE);
    }
    
    if (strcmp(method, "GET") != 0) {
        send_error_response(client_fd, HTTP_501);
        close(client_fd);
        exit(EXIT_FAILURE);
    }
    
    char full_path[MAX_PATH_LENGTH];
    snprintf(full_path, sizeof(full_path), "%s%s", 
             WEBROOT, (strcmp(path, "/") == 0) ? "/index.html" : path);
    
    if (!is_path_safe(full_path)) {
        send_error_response(client_fd, HTTP_403);
        close(client_fd);
        exit(EXIT_FAILURE);
    }
    
    int file_fd = open(full_path, O_RDONLY);
    if (file_fd < 0) {
        send_error_response(client_fd, HTTP_404);
        close(client_fd);
        exit(EXIT_FAILURE);
    }
    
    struct stat file_stat;
    if (fstat(file_fd, &file_stat) < 0) {
        close(file_fd);
        send_error_response(client_fd, HTTP_500);
        close(client_fd);
        exit(EXIT_FAILURE);
    }
    
    const char* content_type = get_content_type(full_path);
    send_http_response(client_fd, HTTP_200, content_type, file_stat.st_size);
    
    off_t offset = 0;
    sendfile(client_fd, file_fd, &offset, file_stat.st_size);
    
    close(file_fd);
    close(client_fd);
    exit(EXIT_SUCCESS);
}
int main() {
    // 设置SIGCHLD处理器
    struct sigaction sa;
    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
    
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }
    
    int server_fd = create_socket();
    bind_socket(server_fd);
    
    if (listen(server_fd, 128) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    
    printf("[Process] Web server running on port %d...\n", PORT);
    
    while (1) {
        struct sockaddr_in client_addr;
        socklen_t addr_len = sizeof(client_addr);
        int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);
        
        if (client_fd < 0) {
            perror("accept");
            continue;
        }
        
        pid_t pid = fork();
        if (pid == 0) { // 子进程
            close(server_fd);
            process_request(client_fd);
        } else if (pid > 0) { // 父进程
            close(client_fd);
        } else {
            perror("fork");
            close(client_fd);
        }
    }
    
    close(server_fd);
    return 0;
}