C/C++服务端无返回时客户端如何快速检测socket/以太网连接断开
客户端TCP连接实时检测解决方案
问题根因
- 仅服务端开启了TCP keepalive,客户端未开启对应配置,无法主动感知链路断开、服务端进程异常退出、网线拔掉等故障
- TCP原生
send接口只要内核socket缓冲区尚有剩余空间就会返回成功,哪怕连接已经处于半开状态,仅判断send返回值无法及时识别断连 - 现有客户端无任何连接存活检测逻辑,断连后仍会持续向无效socket写入数据,导致业务数据丢失
修复方案
我们直接复用现有服务端的TCP keepalive机制,仅修改客户端即可实现秒级断连检测,无需改动服务端逻辑:
- 客户端连接成功后,为socket开启TCP keepalive,配置和服务端对齐的探测参数:
- 10秒无交互就发起探测
- 连续2次探测失败就判定连接断开
- 探测报文间隔2秒
总检测耗时最多14秒,可根据业务需要调整参数实现更快的检测速度
- 增加
send返回值的错误判断,检测到断连后直接退出业务逻辑,关闭socket,避免无效写入
修正后客户端代码
#include<stdio.h> #include<string.h> #include<sys/socket.h> #include<arpa/inet.h> #include <unistd.h> #include <netinet/tcp.h> #include<iostream> #include <errno.h> int main(int argc , char *argv[]) { int socket_desc; struct sockaddr_in server; char *message; socket_desc = socket(AF_INET , SOCK_STREAM , 0); if (socket_desc == -1) { printf("Could not create socket"); return -1; } server.sin_addr.s_addr = inet_addr("192.168.4.28"); server.sin_family = AF_INET; server.sin_port = htons( 6000 ); if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) { puts("connect error"); close(socket_desc); return 1; } // 新增:客户端开启TCP keepalive配置 int flags = 1; if (setsockopt(socket_desc, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags))) { perror("ERROR: setsocketopt(), SO_KEEPALIVE"); close(socket_desc); return -1; }; flags = 10; if (setsockopt(socket_desc, SOL_TCP, TCP_KEEPIDLE, (void *)&flags, sizeof(flags))) { perror("ERROR: setsocketopt(), TCP_KEEPIDLE"); close(socket_desc); return -1; }; flags = 2; if (setsockopt(socket_desc, SOL_TCP, TCP_KEEPCNT, (void *)&flags, sizeof(flags))) { perror("ERROR: setsocketopt(), TCP_KEEPCNT"); close(socket_desc); return -1; }; flags = 2; if (setsockopt(socket_desc, SOL_TCP, TCP_KEEPINTVL, (void *)&flags, sizeof(flags))) { perror("ERROR: setsocketopt(), TCP_KEEPINTVL"); close(socket_desc); return -1; }; puts("Connected\n"); message = "test"; for(int i = 1; i < 10000; i++) { sleep(1); //Send some data ssize_t send_ret = send(socket_desc , message , strlen(message) , 0); if( send_ret < 0) { printf("Send failed, errno:%d, error info:%s, connection broken, exit\n", errno, strerror(errno)); break; } std::cout << i << ". test data send" << std::endl; } close(socket_desc); return 0; }
验证说明
修改后拔掉网线或者直接杀服务端进程,客户端会在最多14秒内检测到连接异常,退出发送循环,不会再继续写入无效数据。如果需要更快的检测速度,可以调整TCP_KEEPIDLE、TCP_KEEPCNT、TCP_KEEPINTVL三个参数,比如设置为2s空闲、3次探测、1s间隔,最快5秒即可识别断连。
内容的提问来源于stack exchange,提问作者tryingBetter
相关产品推荐
相关产品推荐

