C语言Socket客户端突然断开时服务器Segfault段错误如何解决
问题解决与代码优化方案
一、段错误核心原因与修复
段错误的根本原因是服务端检测到客户端断开后,没有终止当前连接的处理逻辑,后续对空数据做字符串拆分、数组访问触发了空指针解引用:
当客户端突然断开时,服务端read调用返回0,你仅将clientSocket[h]设为0,没有跳过后续的报文处理代码,此时msg缓冲区无有效数据,strtok返回NULL,arr[0]、arr[1]都是野指针,访问直接触发段错误。
修复代码片段(服务端read逻辑部分)
READ = read(sd, msg, sizeof(msg)); if (READ == -1) { perror("Could not receive message"); close(sd); clientSocket[h] = 0; continue; // 出错只关闭当前连接,不要退出整个服务端 } if (READ == 0) { printf("Client disconnected\n"); fflush(stdout); close(sd); // 必须关闭断开的socket,避免资源泄漏 clientSocket[h] = 0; continue; // 跳过后续报文处理逻辑,避免访问无效数据 } // 手动给read到的数据加字符串结束符,read不会自动补 msg[READ] = '\0'; int e = 0; char *p = strtok(msg, " "); char *arr[2]; // 加边界判断,避免数组越界 while (p != NULL && e < 2) { arr[e++] = p; p = strtok(NULL, " "); } // 必须校验参数数量,避免非法报文触发越界 if (e != 2) { strcpy(reply, "Input error: please send two numbers separated by space\n"); write(sd, reply, strlen(reply)); continue; }
修改后即可解决客户端断开触发的段错误问题。
二、其他可优化点
- 资源泄漏修复:原来的代码不管是连接出错还是客户端断开,都没有调用
close(sd)释放文件描述符,长期运行会耗尽系统socket资源 - 服务端可用性优化:原来代码只要单连接出错就直接退出整个服务端,改成仅关闭出错的客户端连接,服务端持续运行
- 输入安全修复:客户端
scanf("%s", buf)没有限制输入长度,容易触发栈溢出,改成scanf("%1023s", buf)限制输入长度;fflush(stdin)是C标准未定义行为,不要使用,可用getchar()循环读走缓冲区残留数据 - TCP粘包处理:当前代码没有处理TCP粘包问题,可能出现一次read读到多组报文、或者一组报文被拆分多次读取的情况,建议约定消息边界(比如固定长度、或者用换行符作为结束标识)
- 规范变量命名:不要用
READ、SELECT、ACCEPT这类和系统调用同名的变量,容易引发编译或逻辑异常,改成read_len、select_ret、accept_fd这类自定义命名 - 输入校验优化:
atoi无法区分输入是0还是非法字符串,建议换成strtol做数字转换,可以明确检测转换失败的场景 - 逻辑bug修复:
accept的第二个参数是用来存储客户端地址的,你当前传了&server会覆盖服务端地址配置,改成&client即可;listen的backlog参数设为1太小,并发稍高就会拒绝连接,可改成10或更大值
内容的提问来源于stack exchange,提问作者user14773854
相关产品推荐
相关产品推荐

