C Socket服务器向所有客户端发消息时出现SIGPIPE错误求助
解决C Socket服务器SIGPIPE错误问题
SIGPIPE错误本质是向已断开的TCP连接发送数据,系统默认会触发该信号终止进程。你的代码中有两处send存在触发风险,下面逐一分析并给出修复方案:
一、两处send的问题点
1. 广播消息的循环send
这段循环向其他客户端转发消息时,没有过滤无效的socket描述符:
for ( int client= 0 ; client < max_clients ; client++) { sd_test = client_socket[client]; if (sd_test != sd_new) { send(sd_test , newString.c_str() , strlen(newString.c_str()) , 0 ); } }
- 问题:
client_socket[client]可能是0(未被占用的位置),或者对应的客户端已断开但未被服务器清理,此时调用send会触发SIGPIPE。
2. 循环外的独立send
代码末尾的send(sd_new , last_send.c_str() , strlen(last_send.c_str()) , 0 );
- 问题:
sd_new仅在收到以:开头的消息时才会赋值,初次运行或未收到这类消息时,sd_new是未初始化的垃圾值;即使初始化过,对应的客户端也可能已断开,触发SIGPIPE。
二、具体修复步骤
1. 忽略SIGPIPE信号(基础防护)
在main函数开头添加代码,让系统忽略SIGPIPE信号,此时send遇到断开连接时会返回-1而非终止进程:
signal(SIGPIPE, SIG_IGN);
2. 修复广播循环的send逻辑
添加socket有效性检查,并处理发送失败的情况:
for ( int client= 0 ; client < max_clients ; client++) { sd_test = client_socket[client]; // 只向有效且非当前发送者的socket发送 if (sd_test > 0 && sd_test != sd_new) { ssize_t ret = send(sd_test, newString.c_str(), newString.length(), 0); if (ret == -1) { // 若为连接断开类错误,清理该socket if (errno == EPIPE || errno == ECONNRESET) { getpeername(sd_test, (struct sockaddr*)&address, (socklen_t*)&addrlen); printf("Client disconnected (send failed), ip %s , port %d \n", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); close(sd_test); client_socket[client] = 0; } } } }
3. 修复循环外的send问题
这段send的逻辑模糊,建议根据需求调整:
- 如果是广播收集的
last_send消息,改为遍历所有有效客户端发送:
if (!last_send.empty()) { for (int client = 0; client < max_clients; client++) { sd_test = client_socket[client]; if (sd_test > 0) { ssize_t ret = send(sd_test, last_send.c_str(), last_send.length(), 0); if (ret == -1 && (errno == EPIPE || errno == ECONNRESET)) { getpeername(sd_test, (struct sockaddr*)&address, (socklen_t*)&addrlen); printf("Client disconnected (send failed), ip %s , port %d \n", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); close(sd_test); client_socket[client] = 0; } } } last_send.clear(); // 发送后清空缓存 }
- 如果不需要这段逻辑,直接删除即可。
4. 初始化未赋值变量
在main开头初始化sd_new为无效值,避免未定义行为:
int master_socket , addrlen , new_socket , client_socket[30] , max_clients = 30 , activity, i , valread , sd, sd_new = -1;
三、额外优化建议
- 定期清理
client_socket数组中的无效描述符,避免残留失效的socket; - 处理
send的部分发送情况(返回值小于发送长度时,需循环发送剩余数据); - 用
FD_ISSET检测socket时,先判断sd > 0,避免无效描述符干扰。
内容的提问来源于stack exchange,提问作者user19095524
相关产品推荐
相关产品推荐

