使用epoll检测网线拔出错误
Detect network cable unplugged errors with epoll
我测试过epoll
网线拔掉的情况:
- 服务器打开3000端口
- 创建epoll并将
server_fd
加入epoll
- accept client(client使用
telnet
)并添加client_fd
到epoll
- 向客户端发送数据
- 拔下电缆后,
epoll_wait
永远不会收到与 client_fd
相关的任何事件
我想检测这种情况下的错误。有没有额外的解决方案?应用程序是否需要实现心跳方法进行自我检测?
Telnet 服务器使用 TCP keepalive;事实上,这就是它真正被发明的目的。
您可以时常发送无害的 Telnet 命令。
这两者最终导致 ECONNRESET
。
这里有两个选择:
- 实现应用层心跳。换句话说,您编写代码来检测空闲连接并定期发送应用层消息以实质上探测连接并确保它仍处于打开状态
- 您使用了 TCP 保活。这基本上将实现和处理心跳消息的工作转移到 TCP 层。这对你来说似乎是个不错的选择。
要启用和配置 TCP keepalive,您需要将 client_fd
套接字选项更改为 setsockopts(2)
。您需要检查/更改 3 个参数:
TCP_KEEPCNT
- 这是在任何给定时间允许的未解决的、未答复的调查数。如果在给定的时间间隔内发送超过 TCP_KEEPCNT
次探测而没有回复,则假定连接已断开。
TCP_KEEPIDLE
- 在开始发送探测数据包之前连接需要空闲的时间量。
TCP_KEEPINTVL
- 各个探测之间的时间。
所以,你在 client_fd
上做了这样的事情:
int tcp_keepcnt = 3;
int tcp_keepidle = 30;
int tcp_keepintvl = 60;
setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPCNT, &tcp_keepcnt, sizeof(tcp_keepcnt));
setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle));
setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl));
断开的连接被 epoll(7)
报告为可读,带有 EPOLLHUP
标志。请注意,订单关闭将被报告为可读 没有 EPOLLHUP
,但是 read(2)
将 return 0.
请记住,检测到死连接不是立竿见影的。这需要一段时间。比如上面的参数,大概需要3分钟。
我测试过epoll
网线拔掉的情况:
- 服务器打开3000端口
- 创建epoll并将
server_fd
加入epoll - accept client(client使用
telnet
)并添加client_fd
到epoll - 向客户端发送数据
- 拔下电缆后,
epoll_wait
永远不会收到与client_fd
相关的任何事件
我想检测这种情况下的错误。有没有额外的解决方案?应用程序是否需要实现心跳方法进行自我检测?
Telnet 服务器使用 TCP keepalive;事实上,这就是它真正被发明的目的。
您可以时常发送无害的 Telnet 命令。
这两者最终导致 ECONNRESET
。
这里有两个选择:
- 实现应用层心跳。换句话说,您编写代码来检测空闲连接并定期发送应用层消息以实质上探测连接并确保它仍处于打开状态
- 您使用了 TCP 保活。这基本上将实现和处理心跳消息的工作转移到 TCP 层。这对你来说似乎是个不错的选择。
要启用和配置 TCP keepalive,您需要将 client_fd
套接字选项更改为 setsockopts(2)
。您需要检查/更改 3 个参数:
TCP_KEEPCNT
- 这是在任何给定时间允许的未解决的、未答复的调查数。如果在给定的时间间隔内发送超过TCP_KEEPCNT
次探测而没有回复,则假定连接已断开。TCP_KEEPIDLE
- 在开始发送探测数据包之前连接需要空闲的时间量。TCP_KEEPINTVL
- 各个探测之间的时间。
所以,你在 client_fd
上做了这样的事情:
int tcp_keepcnt = 3;
int tcp_keepidle = 30;
int tcp_keepintvl = 60;
setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPCNT, &tcp_keepcnt, sizeof(tcp_keepcnt));
setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle));
setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl));
断开的连接被 epoll(7)
报告为可读,带有 EPOLLHUP
标志。请注意,订单关闭将被报告为可读 没有 EPOLLHUP
,但是 read(2)
将 return 0.
请记住,检测到死连接不是立竿见影的。这需要一段时间。比如上面的参数,大概需要3分钟。