C语言WebServer处理GET请求无文件返回,报错curl: (52) Empty reply from server
问题分析与修复
你的代码存在几个关键错误,直接导致客户端收到空响应:
错误的send调用逻辑
你用send(client_fd, &opened_fd, 256, NULL)把文件描述符的内存地址发给了客户端,这完全不是文件内容。而且send的第四个参数是flags,必须传整数(比如0),不能传NULL。sendfile参数顺序错误(且未正确使用)
注释掉的sendfile调用参数顺序搞反了,正确的sendfile语法是:ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);应当把客户端套接字fd(
client_fd)放在第一个参数,打开的文件fd(opened_fd)放在第二个参数。同时你传的0意味着发送0字节,自然没有内容返回。缺失错误检查
socket、bind、listen、accept、recv、open这些系统调用都可能失败,你没有检查它们的返回值。比如如果index.html不存在,open会返回-1,后续操作全错。未处理请求格式异常
如果收到的请求不符合GET /file ...格式,strchr(f, ' ')会返回NULL,直接解引用*strchr(f, ' ')会导致程序崩溃。
修复后的代码示例
#include <sys/socket.h> #include <sys/types.h> #include <string.h> #include <fcntl.h> #include <sys/uio.h> #include <unistd.h> #include <netinet/in.h> #include <stdio.h> #include <sys/stat.h> #include <errno.h> int main() { int s = socket(AF_INET, SOCK_STREAM, 0); if (s == -1) { perror("socket failed"); return 1; } struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(8080); addr.sin_addr.s_addr = INADDR_ANY; if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { perror("bind failed"); close(s); return 1; } if (listen(s, 10) == -1) { perror("listen failed"); close(s); return 1; } int client_fd = accept(s, NULL, NULL); if (client_fd == -1) { perror("accept failed"); close(s); return 1; } char buffer[256] = {0}; ssize_t recv_len = recv(client_fd, buffer, sizeof(buffer)-1, 0); if (recv_len <= 0) { perror("recv failed or client closed"); close(client_fd); close(s); return 1; } // 解析请求路径 char* f = buffer + 5; char* space_ptr = strchr(f, ' '); if (!space_ptr) { fprintf(stderr, "Invalid request format\n"); close(client_fd); close(s); return 1; } *space_ptr = '\0'; // 打开文件 int opened_fd = open(f, O_RDONLY); if (opened_fd == -1) { perror("open file failed"); close(client_fd); close(s); return 1; } // 获取文件大小 struct stat file_stat; if (fstat(opened_fd, &file_stat) == -1) { perror("fstat failed"); close(opened_fd); close(client_fd); close(s); return 1; } // 使用sendfile发送文件内容 ssize_t sent = sendfile(client_fd, opened_fd, NULL, file_stat.st_size); if (sent == -1) { perror("sendfile failed"); } // 关闭资源 close(opened_fd); close(client_fd); close(s); return 0; }
额外说明
- 运行修复后的代码后,再执行
curl --http0.9 --output - 'http://localhost:8080/index.html'就能正确获取文件内容了。 - 如果你不想用
sendfile,也可以用read读取文件内容到缓冲区,再用send发送给客户端,逻辑类似。 - 生产环境的Web服务器需要处理更多情况(比如并发请求、不同HTTP方法、错误响应等),但这个修复能解决当前的空响应问题。
内容的提问来源于stack exchange,提问作者saulsebrook
相关产品推荐
相关产品推荐

