linux socket tcp server 解决客户端socket断开后, 服务器端进程退出的问题(忽略SIGPIPE信号)

当服务器向已断开的客户端socket发送数据时,系统会发送SIGPIPE信号导致服务器进程终止。为避免这种情况,可以在代码中使用`signal(SIGPIPE, SIG_IGN)`忽略该信号,确保服务器稳定运行。此方法适用于处理客户端突然断开连接的问题,确保服务端的健壮性。

当服务器监听并接受一个客户端链接的时候, 可以不断向客户端发送数据, 这时如果客户端断开socket链接, 服务器继续向一个关闭的socket 发送数据(send, write)的时候, 系统会默认对服务器进程发送一个SIGPIPE信号, 这个信号的默认动作就是终止当前服务器进程.

所以为了解决客户端断开后导致服务器进程结束的问题, 可在线程中(任意位置)加入下面这一句代码来忽略SIGPIPE信号:

signal(SIGPIPE, SIG_IGN);

需要加入的头文件是:sys/signal.h

### 判断 Linux TCP 客户端 Socket 连接断开的方法 在 Linux 环境下,TCP 客户端可以通过多种方法检测 Socket 连接是否已经断开。以下是几种常见的解决方案或方法: #### 1. 使用 `setsockopt` 配置 SO_KEEPALIVE SO_KEEPALIVE 是一种机制,允许内核定期发送探测包以检查对端是否仍然存活。如果对端在网络中断开或无法响应,客户端可以及时感知到连接状态的变化[^1]。 ```c int enable_keepalive = 1; int ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &enable_keepalive, sizeof(enable_keepalive)); if (ret < 0) { perror("setsockopt"); } ``` 通过启用 SO_KEEPALIVE,可以在底层网络层检测连接异常情况,例如对端崩溃或网络通道可用。 #### 2. 检查读写操作的返回值 在正常的 TCP 连接中,读写操作会返回特定的值来表示连接的状态。如果读取时返回 0,则表示对端已关闭连接;如果写入时返回 `-1` 并设置 `errno` 为 `EPIPE` 或 `SIGPIPE`,则表明连接已断开[^3]。 ```c char buffer[1024]; ssize_t bytes_read = read(sockfd, buffer, sizeof(buffer)); if (bytes_read == 0) { printf("Connection closed by peer\n"); } else if (bytes_read < 0) { perror("read"); } ssize_t bytes_written = write(sockfd, "test", 4); if (bytes_written < 0 && errno == EPIPE) { printf("Broken pipe: Connection is broken\n"); } ``` #### 3. 使用超时选项避免阻塞 为了避免无限期阻塞,可以配置 `SO_RCVTIMEO` 和 `SO_SNDTIMEO` 来设置读写操作的超时时间。如果超时发生,则可能意味着连接存在问题。 ```c struct timeval timeout; timeout.tv_sec = 5; // 设置超时时间为 5 秒 timeout.tv_usec = 0; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)); ``` #### 4. 监听连接状态变化(如使用 `select` 或 `poll`) 通过 `select` 或 `poll` 函数监听文件描述符的状态变化,可以检测到连接是否断开。如果文件描述符变为可读但读取结果为 0,则表示连接已关闭。 ```c fd_set readfds; FD_ZERO(&readfds); FD_SET(sockfd, &readfds); struct timeval timeout = { .tv_sec = 5, .tv_usec = 0 }; int activity = select(sockfd + 1, &readfds, NULL, NULL, &timeout); if (activity > 0) { if (FD_ISSET(sockfd, &readfds)) { char buffer[1024]; ssize_t bytes_read = read(sockfd, buffer, sizeof(buffer)); if (bytes_read == 0) { printf("Connection closed by peer\n"); } } } ``` #### 5. 自定义心跳机制 如果应用层需要更精确的连接状态监控,可以实现自定义的心跳机制。客户端服务器定期交换数据包,若超过一定时间未收到响应,则认为连接已断开。 ```python import socket import time def send_heartbeat(sock): try: sock.sendall(b"ping") data = sock.recv(1024) if not data: print("Connection lost") except socket.error as e: print(f"Socket error: {e}") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("127.0.0.1", 8080)) while True: send_heartbeat(sock) time.sleep(5) ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

映秀小子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值