#include "web_server.h"
#include <sys/select.h>
// 创建socket (同多线程版本)
int create_socket() { /* 同multithreaded.c */ }
void bind_socket(int sockfd) { /* 同multithreaded.c */ }
const char* get_content_type(const char* path) { /* 同multithreaded.c */ }
int is_path_safe(const char* path) { /* 同multithreaded.c */ }
void send_http_response(int client_fd, http_status_t status,
const char* content_type, off_t content_length) { /* 同multithreaded.c */ }
void send_error_response(int client_fd, http_status_t status) { /* 同multithreaded.c */ }
int main() {
int server_fd = create_socket();
bind_socket(server_fd);
// 设置非阻塞模式
fcntl(server_fd, F_SETFL, fcntl(server_fd, F_GETFL) | O_NONBLOCK);
if (listen(server_fd, 128) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
fd_set read_fds, write_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_SET(server_fd, &read_fds);
int max_fd = server_fd;
client_state_t clients[MAX_CLIENTS] = {0};
printf("[IO Multiplex] Web server running on port %d...\n", PORT);
while (1) {
fd_set tmp_read = read_fds;
fd_set tmp_write = write_fds;
if (select(max_fd + 1, &tmp_read, &tmp_write, NULL, NULL) < 0) {
perror("select");
continue;
}
// 处理新连接
if (FD_ISSET(server_fd, &tmp_read)) {
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) {
fcntl(client_fd, F_SETFL, fcntl(client_fd, F_GETFL) | O_NONBLOCK);
// 添加到客户端列表
for (int i = 0; i < MAX_CLIENTS; i++) {
if (clients[i].fd == 0) {
clients[i].fd = client_fd;
clients[i].bytes_received = 0;
clients[i].header_sent = 0;
FD_SET(client_fd, &read_fds);
if (client_fd > max_fd) max_fd = client_fd;
break;
}
}
}
}
// 处理客户端请求
for (int i = 0; i < MAX_CLIENTS; i++) {
if (clients[i].fd == 0) continue;
int client_fd = clients[i].fd;
// 读取数据
if (FD_ISSET(client_fd, &tmp_read)) {
ssize_t bytes_read = recv(client_fd,
clients[i].request + clients[i].bytes_received,
MAX_REQUEST_SIZE - clients[i].bytes_received - 1, 0);
if (bytes_read > 0) {
clients[i].bytes_received += bytes_read;
clients[i].request[clients[i].bytes_received] = '\0';
// 检查完整请求
if (strstr(clients[i].request, "\r\n\r\n")) {
char method[16], path[256];
if (sscanf(clients[i].request, "%15s %255s", method, path) == 2 &&
strcmp(method, "GET") == 0) {
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);
clients[i].fd = 0;
FD_CLR(client_fd, &read_fds);
FD_CLR(client_fd, &write_fds);
continue;
}
clients[i].file_fd = open(full_path, O_RDONLY);
if (clients[i].file_fd < 0) {
send_error_response(client_fd, HTTP_404);
close(client_fd);
clients[i].fd = 0;
FD_CLR(client_fd, &read_fds);
FD_CLR(client_fd, &write_fds);
continue;
}
struct stat file_stat;
fstat(clients[i].file_fd, &file_stat);
clients[i].file_size = file_stat.st_size;
clients[i].file_offset = 0;
const char* content_type = get_content_type(full_path);
char header[512];
snprintf(header, sizeof(header),
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n"
"Connection: close\r\n\r\n",
content_type, clients[i].file_size);
memcpy(clients[i].request, header, strlen(header));
clients[i].bytes_received = strlen(header);
clients[i].header_sent = 0;
FD_CLR(client_fd, &read_fds);
FD_SET(client_fd, &write_fds);
} else {
send_error_response(client_fd, HTTP_400);
close(client_fd);
clients[i].fd = 0;
FD_CLR(client_fd, &read_fds);
}
}
} else if (bytes_read == 0 || (bytes_read < 0 && errno != EAGAIN)) {
close(client_fd);
if (clients[i].file_fd > 0) close(clients[i].file_fd);
clients[i].fd = 0;
FD_CLR(client_fd, &read_fds);
FD_CLR(client_fd, &write_fds);
}
}
// 发送数据
if (FD_ISSET(client_fd, &tmp_write)) {
if (!clients[i].header_sent) {
ssize_t bytes_sent = send(client_fd,
clients[i].request + clients[i].header_sent,
clients[i].bytes_received - clients[i].header_sent, 0);
if (bytes_sent > 0) {
clients[i].header_sent += bytes_sent;
} else if (bytes_sent < 0 && errno != EAGAIN) {
close(client_fd);
close(clients[i].file_fd);
clients[i].fd = 0;
FD_CLR(client_fd, &write_fds);
continue;
}
} else {
ssize_t bytes_sent = sendfile(client_fd, clients[i].file_fd,
&clients[i].file_offset,
clients[i].file_size - clients[i].file_offset);
if (bytes_sent <= 0 && errno != EAGAIN) {
close(client_fd);
close(clients[i].file_fd);
clients[i].fd = 0;
FD_CLR(client_fd, &write_fds);
}
}
}
}
}
close(server_fd);
return 0;
}
报错代码如下io_multiplex.c: In function ‘bind_socket’:
io_multiplex.c:6:22: warning: unused parameter ‘sockfd’ [-Wunused-parameter]
void bind_socket(int sockfd) { /* 同multithreaded.c */ }
^
io_multiplex.c: In function ‘get_content_type’:
io_multiplex.c:7:42: warning: unused parameter ‘path’ [-Wunused-parameter]
const char* get_content_type(const char* path) { /* 同multithreaded.c */ }
^
io_multiplex.c: In function ‘is_path_safe’:
io_multiplex.c:8:30: warning: unused parameter ‘path’ [-Wunused-parameter]
int is_path_safe(const char* path) { /* 同multithreaded.c */ }
^
io_multiplex.c: In function ‘send_http_response’:
io_multiplex.c:9:29: warning: unused parameter ‘client_fd’ [-Wunused-parameter]
void send_http_response(int client_fd, http_status_t status,
^
io_multiplex.c:9:54: warning: unused parameter ‘status’ [-Wunused-parameter]
void send_http_response(int client_fd, http_status_t status,
^
io_multiplex.c:10:37: warning: unused parameter ‘content_type’ [-Wunused-parameter]
const char* content_type, off_t content_length) { /* 同multithreaded.c */ }
^
io_multiplex.c:10:57: warning: unused parameter ‘content_length’ [-Wunused-parameter]
const char* content_type, off_t content_length) { /* 同multithreaded.c */ }
^
io_multiplex.c: In function ‘send_error_response’:
io_multiplex.c:11:30: warning: unused parameter ‘client_fd’ [-Wunused-parameter]
void send_error_response(int client_fd, http_status_t status) { /* 同multithreaded.c */ }
^
io_multiplex.c:11:55: warning: unused parameter ‘status’ [-Wunused-parameter]
void send_error_response(int client_fd, http_status_t status) { /* 同multithreaded.c */ }
^
io_multiplex.c: In function ‘main’:
io_multiplex.c:31:5: warning: missing braces around initializer [-Wmissing-braces]
client_state_t clients[MAX_CLIENTS] = {0};
^
io_multiplex.c:31:5: warning: (near initialization for ‘clients[0]’) [-Wmissing-braces]
io_multiplex.c: In function ‘create_socket’:
io_multiplex.c:5:1: warning: control reaches end of non-void function [-Wreturn-type]
int create_socket() { /* 同multithreaded.c */ }
^
io_multiplex.c: In function ‘get_content_type’:
io_multiplex.c:7:1: warning: control reaches end of non-void function [-Wreturn-type]
const char* get_content_type(const char* path) { /* 同multithreaded.c */ }
^
io_multiplex.c: In function ‘is_path_safe’:
io_multiplex.c:8:1: warning: control reaches end of non-void function [-Wreturn-type]
int is_path_safe(const char* path) { /* 同multithreaded.c */ }
^
最新发布