给以下代码添加C99标准注释:#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/wait.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#define PORT 80
#define WEB_ROOT "./web"
#define BUFFER_SIZE 4096
#define MAX_EVENTS 10000
#define MAX_THREADS 100
#define MAX_PROCESSES 10
// 全局配置
typedef struct {
int mode; // 0:epoll, 1:thread, 2:process
int debug;
} ServerConfig;
// HTTP响应模板
const char* http_200 =
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Connection: close\r\n\r\n";
const char* http_404 =
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n"
"<html><body><h1>404 Not Found</h1></body></html>";
const char* http_400 =
"HTTP/1.1 400 Bad Request\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n"
"<html><body><h1>400 Bad Request</h1></body></html>";
// 调试输出
void debug_print(ServerConfig config, const char* format, ...) {
if (!config.debug) return;
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
fflush(stdout);
}
// 获取文件MIME类型
const char* get_mime_type(const char* path) {
const char *ext = strrchr(path, '.');
if (!ext) return "text/plain";
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 || strcmp(ext, ".jpeg") == 0) return "image/jpeg";
if (strcmp(ext, ".png") == 0) return "image/png";
if (strcmp(ext, ".gif") == 0) return "image/gif";
return "text/plain";
}
// 发送文件内容
void send_file(int client_fd, const char* filepath) {
int fd = open(filepath, O_RDONLY);
if (fd < 0) {
write(client_fd, http_404, strlen(http_404));
return;
}
// 获取文件信息
struct stat st;
fstat(fd, &st);
off_t file_size = st.st_size;
// 构建响应头
char header[BUFFER_SIZE];
const char* mime_type = get_mime_type(filepath);
snprintf(header, sizeof(header), http_200, mime_type);
write(client_fd, header, strlen(header));
// 零拷贝发送文件
off_t offset = 0;
while (offset < file_size) {
ssize_t sent = sendfile(client_fd, fd, &offset, file_size - offset);
if (sent <= 0) break;
}
close(fd);
}
// 处理客户端请求
void handle_request(int client_fd, ServerConfig config) {
char buffer[BUFFER_SIZE];
ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);
if (bytes_read <= 0) {
close(client_fd);
return;
}
buffer[bytes_read] = '\0';
debug_print(config, "Received request:\n%s\n", buffer);
// 解析请求行
char method[16], path[256], protocol[16];
if (sscanf(buffer, "%15s %255s %15s", method, path, protocol) != 3) {
write(client_fd, http_400, strlen(http_400));
close(client_fd);
return;
}
// 安全处理:防止路径遍历攻击
if (strstr(path, "..")) {
write(client_fd, http_404, strlen(http_404));
close(client_fd);
return;
}
// 默认页面处理
if (strcmp(path, "/") == 0) {
strcpy(path, "/index.html");
}
char fullpath[512];
snprintf(fullpath, sizeof(fullpath), "%s%s", WEB_ROOT, path);
if (strcmp(method, "GET") == 0) {
send_file(client_fd, fullpath);
}
else if (strcmp(method, "POST") == 0) {
// 查找请求体
char* body = strstr(buffer, "\r\n\r\n");
if (body) body += 4;
else body = "";
char response[BUFFER_SIZE];
snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n"
"<html><body><h1>Received: %s</h1></body></html>",
body);
write(client_fd, response, strlen(response));
}
else {
write(client_fd, http_400, strlen(http_400));
}
close(client_fd);
}
// ================== 多线程模式 ==================
typedef struct {
int client_fd;
ServerConfig config;
} ThreadArgs;
void* thread_handler(void* arg) {
ThreadArgs* args = (ThreadArgs*)arg;
handle_request(args->client_fd, args->config);
free(args);
return NULL;
}
void run_multithread_server(ServerConfig config) {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// 端口复用
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
.sin_port = htons(PORT)
};
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind");
close(server_fd);
exit(EXIT_FAILURE);
}
if (listen(server_fd, 10000) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("Multithread server running on port %d\n", PORT);
while (1) {
int client_fd = accept(server_fd, NULL, NULL);
if (client_fd < 0) {
perror("accept");
continue;
}
ThreadArgs* args = malloc(sizeof(ThreadArgs));
args->client_fd = client_fd;
args->config = config;
pthread_t thread;
if (pthread_create(&thread, NULL, thread_handler, args) != 0) {
perror("pthread_create");
close(client_fd);
free(args);
} else {
pthread_detach(thread);
}
}
}
// ================== 多进程模式 ==================
void run_multiprocess_server(ServerConfig config) {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// 端口复用
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
.sin_port = htons(PORT)
};
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind");
close(server_fd);
exit(EXIT_FAILURE);
}
if (listen(server_fd, 10000) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("Multiprocess server running on port %d\n", PORT);
// 防止僵尸进程
signal(SIGCHLD, SIG_IGN);
while (1) {
int client_fd = accept(server_fd, NULL, NULL);
if (client_fd < 0) {
perror("accept");
continue;
}
pid_t pid = fork();
if (pid == 0) { // 子进程
close(server_fd);
handle_request(client_fd, config);
exit(0);
} else if (pid > 0) { // 父进程
close(client_fd);
} else {
perror("fork");
close(client_fd);
}
}
}
// ================== Epoll模式 ==================
void run_epoll_server(ServerConfig config) {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// 设置非阻塞和端口复用
fcntl(server_fd, F_SETFL, O_NONBLOCK);
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
.sin_port = htons(PORT)
};
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind");
close(server_fd);
exit(EXIT_FAILURE);
}
if (listen(server_fd, 10000) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("Epoll server running on port %d\n", PORT);
// 创建epoll实例
int epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
perror("epoll_create1");
close(server_fd);
exit(EXIT_FAILURE);
}
struct epoll_event event = {
.events = EPOLLIN,
.data.fd = server_fd
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) < 0) {
perror("epoll_ctl");
close(server_fd);
close(epoll_fd);
exit(EXIT_FAILURE);
}
struct epoll_event events[MAX_EVENTS];
while (1) {
int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (n < 0) {
perror("epoll_wait");
continue;
}
for (int i = 0; i < n; i++) {
if (events[i].data.fd == server_fd) {
// 处理新连接
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) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("accept");
}
continue;
}
fcntl(client_fd, F_SETFL, O_NONBLOCK);
struct epoll_event client_event = {
.events = EPOLLIN | EPOLLET, // 边缘触发模式
.data.fd = client_fd
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &client_event) < 0) {
perror("epoll_ctl");
close(client_fd);
}
} else {
// 处理客户端请求
handle_request(events[i].data.fd, config);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
}
}
}
}
int main(int argc, char* argv[]) {
ServerConfig config = {0};
config.debug = 1; // 默认开启调试
// 解析命令行参数
if (argc < 2) {
printf("Usage: %s [--epoll | --thread | --process] [--debug]\n", argv[0]);
return 1;
}
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--epoll") == 0) config.mode = 0;
else if (strcmp(argv[i], "--thread") == 0) config.mode = 1;
else if (strcmp(argv[i], "--process") == 0) config.mode = 2;
else if (strcmp(argv[i], "--debug") == 0) config.debug = 1;
else if (strcmp(argv[i], "--no-debug") == 0) config.debug = 0;
}
// 根据模式启动服务器
switch (config.mode) {
case 0: // epoll
run_epoll_server(config);
break;
case 1: // thread
run_multithread_server(config);
break;
case 2: // process
run_multiprocess_server(config);
break;
default:
printf("Invalid mode\n");
return 1;
}
return 0;
}
最新发布