#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/epoll.h>
#include <fcntl.h>
#include <pthread.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
#include <ctype.h>
#include <errno.h>
#define PORT 8080
#define MAX_EVENTS 1024
#define THREAD_POOL_SIZE 8
#define BUFFER_SIZE 4096
#define WEB_ROOT "web" // 当前目录作为根目录
// 线程池结构
typedef struct {
pthread_t *threads;
int thread_count;
pthread_mutex_t lock;
pthread_cond_t cond;
int shutdown;
} ThreadPool;
// 任务结构
typedef struct {
int client_fd;
struct sockaddr_in client_addr;
} Task;
// 全局任务队列
Task *task_queue;
int task_count = 0;
int task_capacity = 0;
ThreadPool thread_pool;
// HTTP响应头
const char *http_header = "HTTP/1.1 200 OK\r\n"
"Server: SimpleWebServer\r\n"
"Connection: close\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n\r\n";
// 十六进制字符转换
int hex_char_to_int(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return 0;
}
// URL解码
void url_decode(char *dst, const char *src) {
char a, b;
while (*src) {
if (*src == '%' && (a = src[1]) && (b = src[2]) && isxdigit(a) && isxdigit(b)) {
*dst++ = (hex_char_to_int(a) << 4) | hex_char_to_int(b);
src += 3;
} else if (*src == '+') {
*dst++ = ' ';
src++;
} else {
*dst++ = *src++;
}
}
*dst = '\0';
}
// 文件扩展名到MIME类型映射
const char *extension_to_type(const char *ext) {
if (strcmp(ext, "html") == 0) return "text/html";
if (strcmp(ext, "htm") == 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";
if (strcmp(ext, "ico") == 0) return "image/x-icon";
if (strcmp(ext, "json") == 0) return "application/json";
if (strcmp(ext, "txt") == 0) return "text/plain";
if (strcmp(ext, "svg") == 0) return "image/svg+xml";
return "application/octet-stream";
}
// 获取文件扩展名
const char *get_file_extension(const char *filename) {
const char *dot = strrchr(filename, '.');
if (!dot || dot == filename) return "";
return dot + 1;
}
// 发送404错误响应
void send_404(int client_fd) {
const char *response = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html; charset=UTF-8\r\n"
"Connection: close\r\n"
"Content-Length: 86\r\n\r\n"
"<html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1></body></html>";
send(client_fd, response, strlen(response), 0);
}
// 发送400错误响应
void send_400(int client_fd) {
const char *response = "HTTP/1.1 400 Bad Request\r\n"
"Content-Type: text/html; charset=UTF-8\r\n"
"Connection: close\r\n"
"Content-Length: 84\r\n\r\n"
"<html><head><title>400 Bad Request</title></head><body><h1>400 Bad Request</h1></body></html>";
send(client_fd, response, strlen(response), 0);
}
// 发送500错误响应
void send_500(int client_fd) {
const char *response = "HTTP/1.1 500 Internal Server Error\r\n"
"Content-Type: text/html; charset=UTF-8\r\n"
"Connection: close\r\n"
"Content-Length: 92\r\n\r\n"
"<html><head><title>500 Internal Error</title></head><body><h1>500 Internal Server Error</h1></body></html>";
send(client_fd, response, strlen(response), 0);
}
// 处理客户端请求
void handle_request(int client_fd, struct sockaddr_in client_addr) {
char buffer[BUFFER_SIZE];
ssize_t bytes_read = recv(client_fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_read <= 0) {
close(client_fd);
return;
}
buffer[bytes_read] = '\0';
// 解析HTTP请求
char method[16], path[256], protocol[16];
if (sscanf(buffer, "%s %s %s", method, path, protocol) != 3) {
send_400(client_fd);
close(client_fd);
return;
}
// 日志输出
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
printf("[%s] %s %s %s\n", client_ip, method, path, protocol);
// URL解码
char decoded_path[256];
url_decode(decoded_path, path);
printf("Decoded path: %s\n", decoded_path);
// 只处理GET请求
if (strcmp(method, "GET") != 0 && strcmp(method, "POST") != 0) {
send_400(client_fd);
close(client_fd);
return;
}
// 安全处理路径
char safe_path[512];
if (strcmp(decoded_path, "/") == 0) {
// 尝试多个可能的默认文件
const char *default_files = {"Index.html"};
int found = 0;
snprintf(safe_path, sizeof(safe_path), "%s/%s", WEB_ROOT, default_files);
if (access(safe_path, F_OK) == 0) {
found = 1;
}
if (!found) {
strcpy(safe_path, WEB_ROOT "/Index.html");
}
} else {
// 处理路径中的斜杠问题
if (decoded_path[0] == '/') {
snprintf(safe_path, sizeof(safe_path), "%s%s", WEB_ROOT, decoded_path);
} else {
snprintf(safe_path, sizeof(safe_path), "%s/%s", WEB_ROOT, decoded_path);
}
}
printf("Final path: %s\n", safe_path);
// 防止路径遍历攻击
if (strstr(safe_path, "..")) {
printf("Path traversal attempt detected: %s\n", safe_path);
send_404(client_fd);
close(client_fd);
return;
}
// 检查文件是否存在
struct stat file_stat;
if (stat(safe_path, &file_stat) < 0) {
perror("stat failed");
send_404(client_fd);
close(client_fd);
return;
}
// 检查是否是普通文件
if (!S_ISREG(file_stat.st_mode)) {
printf("Not a regular file: %s\n", safe_path);
send_404(client_fd);
close(client_fd);
return;
}
// 检查文件权限
if (access(safe_path, R_OK) != 0) {
perror("access failed");
send_404(client_fd);
close(client_fd);
return;
}
// 打开文件
FILE *file = fopen(safe_path, "rb");
if (!file) {
perror("fopen failed");
send_500(client_fd);
close(client_fd);
return;
}
// 获取MIME类型
const char *ext = get_file_extension(safe_path);
const char *mime_type = extension_to_type(ext);
// 构建HTTP响应头
char header[1024];
snprintf(header, sizeof(header), http_header, mime_type, file_stat.st_size);
// 发送响应头
ssize_t sent = send(client_fd, header, strlen(header), 0);
if (sent <= 0) {
perror("send header failed");
fclose(file);
close(client_fd);
return;
}
// 发送文件内容
char file_buffer[BUFFER_SIZE];
size_t bytes;
while ((bytes = fread(file_buffer, 1, sizeof(file_buffer), file)) > 0) {
sent = send(client_fd, file_buffer, bytes, 0);
if (sent <= 0) {
perror("send file content failed");
break;
}
}
fclose(file);
close(client_fd);
// 打印日志
printf("[%s] %s %s - Sent %ld bytes\n", client_ip, method, decoded_path, file_stat.st_size);
}
// 线程工作函数
void *worker_thread(void *arg) {
while (1) {
pthread_mutex_lock(&thread_pool.lock);
// 等待任务
while (task_count == 0 && !thread_pool.shutdown) {
pthread_cond_wait(&thread_pool.cond, &thread_pool.lock);
}
if (thread_pool.shutdown) {
pthread_mutex_unlock(&thread_pool.lock);
pthread_exit(NULL);
}
// 获取任务
Task task = task_queue[--task_count];
pthread_mutex_unlock(&thread_pool.lock);
// 处理任务
handle_request(task.client_fd, task.client_addr);
}
return NULL;
}
// 初始化线程池
void thread_pool_init(ThreadPool *pool, int thread_count) {
pool->threads = (pthread_t *)malloc(thread_count * sizeof(pthread_t));
if (!pool->threads) {
perror("malloc failed");
exit(EXIT_FAILURE);
}
pool->thread_count = thread_count;
pool->shutdown = 0;
pthread_mutex_init(&pool->lock, NULL);
pthread_cond_init(&pool->cond, NULL);
// 初始化任务队列
task_capacity = 256;
task_queue = (Task *)malloc(task_capacity * sizeof(Task));
if (!task_queue) {
perror("malloc failed");
exit(EXIT_FAILURE);
}
task_count = 0;
// 创建工作线程
for (int i = 0; i < thread_count; i++) {
if (pthread_create(&pool->threads[i], NULL, worker_thread, NULL) != 0) {
perror("pthread_create failed");
exit(EXIT_FAILURE);
}
}
}
// 添加任务到线程池
void add_task(int client_fd, struct sockaddr_in client_addr) {
pthread_mutex_lock(&thread_pool.lock);
// 如果任务队列已满,扩大容量
if (task_count == task_capacity) {
task_capacity *= 2;
Task *new_queue = (Task *)realloc(task_queue, task_capacity * sizeof(Task));
if (!new_queue) {
perror("realloc failed");
pthread_mutex_unlock(&thread_pool.lock);
close(client_fd);
return;
}
task_queue = new_queue;
}
// 添加任务
task_queue[task_count].client_fd = client_fd;
task_queue[task_count].client_addr = client_addr;
task_count++;
// 通知工作线程
pthread_cond_signal(&thread_pool.cond);
pthread_mutex_unlock(&thread_pool.lock);
}
// 设置文件描述符为非阻塞
void set_nonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
perror("fcntl F_GETFL failed");
return;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
perror("fcntl F_SETFL failed");
}
}
int main() {
int server_fd, epoll_fd;
struct sockaddr_in address;
struct epoll_event event, events[MAX_EVENTS];
socklen_t addrlen = sizeof(address);
// 创建服务器socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置socket选项
int opt = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("setsockopt");
close(server_fd);
exit(EXIT_FAILURE);
}
// 绑定地址和端口
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}
// 开始监听
if (listen(server_fd, 128) < 0) {
perror("listen");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("Server listening on port %d\n", PORT);
printf("Web root: %s\n", WEB_ROOT);
// 创建epoll实例
epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
perror("epoll_create1");
close(server_fd);
exit(EXIT_FAILURE);
}
// 添加服务器socket到epoll
event.events = EPOLLIN;
event.data.fd = server_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) < 0) {
perror("epoll_ctl: server_fd");
close(server_fd);
close(epoll_fd);
exit(EXIT_FAILURE);
}
// 初始化线程池
thread_pool_init(&thread_pool, THREAD_POOL_SIZE);
printf("Thread pool initialized with %d threads\n", THREAD_POOL_SIZE);
// 主循环
while (1) {
int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nfds < 0) {
perror("epoll_wait");
break;
}
for (int i = 0; i < nfds; 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) {
perror("accept");
continue;
}
// 设置非阻塞
set_nonblocking(client_fd);
// 添加客户端socket到epoll
event.events = EPOLLIN | EPOLLET;
event.data.fd = client_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) < 0) {
perror("epoll_ctl: client_fd");
close(client_fd);
continue;
}
// 打印新连接信息
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
printf("New connection from %s:%d\n", client_ip, ntohs(client_addr.sin_port));
} else {
// 处理客户端请求
int client_fd = events[i].data.fd;
// 获取客户端地址
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
if (getpeername(client_fd, (struct sockaddr *)&client_addr, &addr_len) < 0) {
perror("getpeername failed");
close(client_fd);
continue;
}
// 将任务添加到线程池
add_task(client_fd, client_addr);
// 从epoll中移除,避免重复处理
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL);
}
}
}
// 清理
close(server_fd);
close(epoll_fd);
// 关闭线程池
thread_pool.shutdown = 1;
pthread_cond_broadcast(&thread_pool.cond);
for (int i = 0; i < thread_pool.thread_count; i++) {
pthread_join(thread_pool.threads[i], NULL);
}
free(thread_pool.threads);
free(task_queue);
return 0;
}
以这一版为准
运行后,windows浏览器偶尔会对GET请求报错:net:ERR_CONTENT_LENGTH_MISMATCH
最新发布