客户端断开连接后Socket服务器崩溃问题排查
问题原因分析
从GDB dump可以直接定位崩溃根因:Linux系统中,向已经断开的TCP套接字执行send操作时,内核会向进程发送SIGPIPE信号,该信号的默认处理动作是直接终止进程,和代码逻辑错误无关。
修复方案
你需要做以下几处修改:
- 全局忽略SIGPIPE信号
在服务端初始化逻辑(比如main函数启动阶段)添加以下代码,让系统遇到SIGPIPE时不终止进程,而是让send调用正常返回错误码:
- 全局忽略SIGPIPE信号
#include <signal.h> // 放在main函数最开头即可 signal(SIGPIPE, SIG_IGN);
- 补全错误处理逻辑,清理失效套接字
你当前的代码只打印错误,没有把断开的客户端从client_pool中移除,也没有关闭无效套接字,会导致重复报错和资源泄漏。修改后的心跳逻辑参考:
- 补全错误处理逻辑,清理失效套接字
void * client_hartbeat() { int i; char send_msg[50] = "e"; char recv_msg[50]; while(1) { sleep(3); printf("\nchecking for disconnected clients\n"); memset(recv_msg,0,sizeof(recv_msg)); for(i=0;i<CLIENTS;i++){ if(client_pool[i]!=0){ // pthread_self()在Linux下是unsigned long类型,用%lu打印更规范 printf("TEST0, socket: %i thread: %lu\n", client_pool[i], (unsigned long)pthread_self()); ssize_t send_ret = send(client_pool[i], send_msg, sizeof(send_msg), 0); if(send_ret < 0){ printf("send error fd %d: %s, close client\n", client_pool[i], strerror(errno)); close(client_pool[i]); client_pool[i] = 0; // 从连接池移除 continue; } ssize_t recv_ret = recv(client_pool[i], recv_msg, sizeof(recv_msg), 0); if(recv_ret <= 0){ // 对端正常断开时recv会返回0,也要处理 printf("recv error fd %d: %s, close client\n", client_pool[i], strerror(errno)); close(client_pool[i]); client_pool[i] = 0; continue; } printf("TEST1, socket: %i thread: %lu\n", client_pool[i], (unsigned long)pthread_self()); } } } pthread_exit(&th2); }
- 其他注意事项
如果你的client_pool是多线程共享的,需要加互斥锁保护,避免其他线程操作连接池时和心跳线程出现竞态条件,引发未知错误。
- 其他注意事项
内容的提问来源于stack exchange,提问作者hairo
相关产品推荐
相关产品推荐

