C语言HTTP服务器报错:bind地址占用、socket打开文件过多及段错误求助
C语言HTTP服务器问题排查与修复
问题汇总
- 运行时偶尔报错
bind: address already in use - 当前报错
socket: too many open files - 程序会因段错误退出
代码问题分析与修复方案
1. 构造函数未返回值导致段错误
server_constructor函数声明返回struct Server,但函数末尾没有返回创建的server结构体,这会触发未定义行为,直接引发段错误。
修复:在函数末尾添加return server;
2. 客户端套接字未关闭导致文件描述符泄漏
launch函数中,每次accept获取客户端套接字后,处理完请求没有调用close(client_socket),导致每个连接的套接字持续占用文件描述符,累积超过进程限制后就会报错too many open files。
修复:在write操作完成后添加close(client_socket);
3. 读取请求时长度参数错误
read(client_socket, buffer, strlen(buffer))中,buffer初始化为全0,strlen(buffer)返回0,导致完全读取不到客户端请求数据。应该用sizeof(buffer)-1作为读取长度(预留一个字节存放字符串终止符)。
修复:将strlen(buffer)改为sizeof(buffer)-1
4. 端口占用问题
程序退出后,端口会处于TIME_WAIT状态,短时间内无法重新绑定,导致bind: address already in use。需要给监听套接字设置SO_REUSEADDR选项。
修复:在bind之前添加如下代码:
int opt = 1; if (setsockopt(server.socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt"); exit(1); }
5. 监听套接字关闭语句不可达
close(server->socket)放在while(1)循环之后,永远不会执行到,属于代码瑕疵,可忽略,后续若处理信号可在信号处理函数中补充关闭逻辑。
修复后的完整代码
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<arpa/inet.h> #include<netdb.h> #include<netinet/in.h> #include<sys/socket.h> #include<unistd.h> struct Server{ int domain; int service_type; int protocol; __u_long interface; int port; int backlog; struct sockaddr_in address; int socket; void (*launch)(struct Server *server); }; struct Server server_constructor(int domain, int service, int protocol, __u_long interface, int port, int backlog, void (* launch)(struct Server* server)){ struct Server server; server.domain = domain; server.service_type = service; server.protocol = protocol; server.interface = interface; server.port = port; server.backlog = backlog; server.address.sin_port = htons(server.port); server.address.sin_family = server.domain; server.address.sin_addr.s_addr = htonl(server.interface); memset(server.address.sin_zero, '\0', sizeof server.address.sin_zero); server.socket = socket(server.domain, server.service_type, server.protocol); if(server.socket < 0){ perror("socket"); exit(1); } // 设置端口复用,解决address already in use问题 int opt = 1; if (setsockopt(server.socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt"); exit(1); } int bind_stat = bind(server.socket, (struct sockaddr*)&server.address, sizeof(server.address)); if(bind_stat < 0){ perror("bind"); exit(1); } printf("Binding Sucessful\n"); int listen_stat = listen(server.socket, server.backlog); if(listen_stat < 0){ perror("listen"); exit(1); } printf("Listening on port %d\n", server.port); server.launch = launch; // 修复:返回构造的server结构体 return server; } void launch(struct Server *server){ int addr_len = sizeof(server->address); char *hello = "HTTP/1.1 200 OK\nContent-Type: text/plain\n\nHello world!"; char buffer[300000] = {0}; while (1) { printf("\n++++++++++++++ Listening for connections ++++++++++++++\n"); int client_socket = accept(server->socket, (struct sockaddr * )& server->address, (socklen_t*)&addr_len); if(client_socket < 0){ perror("accept"); exit(EXIT_FAILURE); } memset(buffer, 0, sizeof(buffer)); // 修复:用sizeof(buffer)-1作为读取长度,确保有终止符空间 read(client_socket, buffer, sizeof(buffer)-1); printf("%s\n", buffer); write(client_socket, hello, strlen(hello)); printf("\n++++++++++++++++ Response message sent ++++++++++++++++\n"); // 修复:关闭客户端套接字,释放文件描述符 close(client_socket); } close(server->socket); } int main(){ struct Server server = server_constructor(AF_INET, SOCK_STREAM, 0, INADDR_ANY, 9988, 5, launch); server.launch(&server); return 0; }
内容的提问来源于stack exchange,提问作者Dying Falcon
相关产品推荐
相关产品推荐

