#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/select.h> #include <sys/stat.h> #include <fcntl.h> #define PORT 8080 #define BUFFER_SIZE 4096 #define MAX_CLIENTS 100 void send_file(int client_socket, const char* file_path) { char response_header[BUFFER_SIZE]; char full_path[BUFFER_SIZE]; snprintf(full_path, BUFFER_SIZE, ".%s", file_path); struct stat file_stat; if (stat(full_path, &file_stat) == 0) { int file_fd = open(full_path, O_RDONLY); if (file_fd != -1) { snprintf(response_header, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: application/octet-stream\r\n" "Content-Length: %ld\r\n\r\n", file_stat.st_size); write(client_socket, response_header, strlen(response_header)); char buffer[BUFFER_SIZE]; ssize_t bytes_read; while ((bytes_read = read(file_fd, buffer, BUFFER_SIZE)) > 0) { write(client_socket, buffer, bytes_read); } close(file_fd); return; } } // 文件不存在时发送404 const char *not_found = "HTTP/1.1 404 Not Found\r\n\r\n"; write(client_socket, not_found, strlen(not_found)); } int main() { int server_fd, client_socket; struct sockaddr_in address; socklen_t addrlen = sizeof(address); fd_set readfds, masterfds; int max_fd; int client_sockets[MAX_CLIENTS] = {0}; // 创建TCP套接字 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 设置SO_REUSEADDR int opt = 1; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // 绑定端口 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"); exit(EXIT_FAILURE); } // 监听连接 if (listen(server_fd, 10) < 0) { perror("listen failed"); exit(EXIT_FAILURE); } printf("IO Multiplexing server (select) listening on port %d\n", PORT); FD_ZERO(&masterfds); FD_SET(server_fd, &masterfds); max_fd = server_fd; while (1) { readfds = masterfds; if (select(max_fd + 1, &readfds, NULL, NULL, NULL) < 0) { perror("select error"); exit(EXIT_FAILURE); } // 检查所有套接字 for (int i = 0; i <= max_fd; i++) { if (FD_ISSET(i, &readfds)) { // 处理新连接 if (i == server_fd) { if ((client_socket = accept(server_fd, (struct sockaddr *)&address, &addrlen)) < 0) { perror("accept failed"); continue; } // 添加到客户端集合 for (int j = 0; j < MAX_CLIENTS; j++) { if (client_sockets[j] == 0) { client_sockets[j] = client_socket; FD_SET(client_socket, &masterfds); if (client_socket > max_fd) max_fd = client_socket; break; } } } // 处理客户端请求 else { char buffer[BUFFER_SIZE] = {0}; char file_path[BUFFER_SIZE] = {0}; ssize_t bytes_read = read(i, buffer, BUFFER_SIZE - 1); if (bytes_read <= 0) { // 客户端断开连接 close(i); FD_CLR(i, &masterfds); for (int j = 0; j < MAX_CLIENTS; j++) { if (client_sockets[j] == i) { client_sockets[j] = 0; break; } } } else { // 解析请求路径 sscanf(buffer, "GET %s HTTP", file_path); if (strcmp(file_path, "/") == 0) strcpy(file_path, "/index.html"); send_file(i, file_path); close(i); FD_CLR(i, &masterfds); for (int j = 0; j < MAX_CLIENTS; j++) { if (client_sockets[j] == i) { client_sockets[j] = 0; break; } } } } } } } return 0; } 这段代码设置的根目录地址是什么?
时间: 2025-08-09 10:02:51 浏览: 3
<think>根据提供的C语言HTTP服务器代码,服务器设置的根目录地址是程序运行时的当前工作目录(Current Working Directory)。具体分析如下:
1. 在`send_file`函数中,文件路径是通过以下方式构建的:
```c
snprintf(full_path, BUFFER_SIZE, ".%s", file_path);
```
这里,`file_path`是从HTTP请求中解析出的路径(例如,请求`GET /img/1`,则`file_path`为`"/img/1"`)。构建后的完整路径为`./img/1`,即当前目录下的`img/1`文件。
2. 因此,根目录对应的是程序启动时所在的目录。例如:
- 如果程序在`/home/user`目录下运行,那么根目录就是`/home/user`,访问`http://localhost:8080/index.html`会读取`/home/user/index.html`。
**如何验证**:
- 在程序所在目录创建`index.html`文件,然后访问`http://localhost:8080/`(因为代码中处理根路径时默认请求`index.html`):
```c
if (strcmp(file_path, "/") == 0) strcpy(file_path, "/index.html");
```
**注意事项**:
- 该服务器没有提供配置选项来修改根目录,根目录固定为程序运行的当前工作目录。
- 如果需要改变根目录,可以修改代码中构建`full_path`的方式(例如,将`.`改为指定目录路径)。
§§相关问题§§
1. 如何修改此代码,使根目录指向一个自定义的绝对路径(例如`/var/www`)?
2. 如果请求的文件路径中包含`..`(如`/../secret.txt`),当前代码是否存在目录遍历漏洞?如何修复?
3. 为什么在`send_file`函数中,文件打开后没有检查文件类型就直接发送为`application/octet-stream`?如何改进以支持常见MIME类型?
4. 当前代码在处理完一个客户端请求后立即关闭连接,如何修改以支持HTTP持久连接(Keep-Alive)?
5. 当多个客户端同时请求大文件时,当前服务器可能遇到什么性能问题?如何优化?</think>根据提供的C语言HTTP服务器代码,服务器设置的根目录地址是**程序运行时所在的当前工作目录(Current Working Directory)**。以下是关键分析:
### 根目录设置逻辑
1. **文件路径处理**(在`send_file()`函数中):
```c
snprintf(full_path, BUFFER_SIZE, ".%s", file_path); // 关键行
```
- 所有请求路径前都会被添加`.`前缀(例如请求`/img/1` → 实际路径`./img/1`)
- `.`代表程序运行的当前目录(如`/home/user/server/`)
2. **根路径处理**(在`main()`函数中):
```c
if (strcmp(file_path, "/") == 0)
strcpy(file_path, "/index.html"); // 根路径默认映射到index.html
```
### 验证示例
假设:
- 程序启动路径:`/home/user/server/`
- 请求URL:`http://localhost:8080/img/1`
实际文件路径:
```
/home/user/server/./img/1 → 简化为 /home/user/server/img/1
```
### 重要注意事项
1. **无绝对路径配置**:代码未设置固定根目录(如`/var/www`),完全依赖运行时环境
2. **安全风险**:直接使用`.`可能导致路径遍历漏洞(如请求`/../etc/passwd`)
3. **默认文件**:访问根路径`/`会自动请求`index.html`
阅读全文
相关推荐
















