1、简介
在长连接中, 客户端和服务器之间定期发送一个固定信息给服务器端, 通知对方自己还在线,以确保连接的有效性。
在服务器和客户端之间一定时间内没有数据交互时,即处于 idle 状态时,客户端或服务器会发送一个特殊的数据包(即心跳包)给对方,当接收方收到这个数据报文后,也立即发送一个特殊的数据报文,回应发送方, 这就是一个 PING-PONG 交互。 当某一端收到心跳消息后,就知道了对方仍然在线,这就确保 TCP 连接的有效性。
2、实现
两种方式实现心跳机制:
- 使用 TCP 协议层面的 keepalive 机制
- 在应用层上实现自定义的心跳机制
虽然在 TCP 协议层面上, 提供了 keepalive 保活机制, 但是使用它有几个缺点:
- 它不是 TCP 的标准协议, 并且是默认关闭的.
- TCP keepalive 机制依赖于操作系统的实现, 默认的 keepalive 心跳时间是 两个小时, 并且对 keepalive 的修改需要系统调用(或者修改系统配置), 灵活性不够.
- TCP keepalive 与 TCP 协议绑定, 因此如果需要更换为 UDP 协议时, keepalive 机制就失效了.
使用 TCP 层面的 keepalive 机制比自定义的应用层心跳机制节省流量
2.1 应用层
-
HTTP长连接中的Keep-Alive:
原理: HTTP协议的Keep-Alive机制允许在单个TCP连接上发送和接收多个HTTP请求和响应,避免了每次请求都建立新的TCP连接。
应用场景: 在Web服务中,通过保持TCP连接的持久性来提高网络性能,减少连接建立和断开的开销。
-
WebSocket中的Ping/Pong帧:
原理: WebSocket通过应用层的Ping/Pong帧来实现心跳机制。客户端定期发送Ping帧到服务器,服务器接收到后回复Pong帧,以确认连接仍然有效。
应用场景: 用于长连接场景,如实时通讯、在线游戏等,确保连接的稳定性和及时性。
2.2 传输层
- TCP: TCP协议本身提供了一种称为keep-alive的机制,可以在连接空闲一段时间后自动发送探测报文,检测对端是否仍然在线。具体实现依赖于操作系统的TCP/IP协议栈,通常可以通过套接字选项进行配置。默认KeepAlive状态是不打开的。需要将setsockopt将SOL_SOCKET.SO_KEEPALIVE设置为1才是打开KeepAlive状态
// 设置TCP Keep-Alive参数
int optval = 1;
int keepidle = 60; // 开始首次Keep-Alive探测前的空闲时间(秒)
int keepintvl = 10; // 两次Keep-Alive探测间的时间间隔(秒)
int keepcnt = 3; // 未收到回复的Keep-Alive探测的次数
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
- UDP: 虽然UDP是无连接的协议,但在一些应用中可以模拟心跳机制来确认数据包的发送和接收状态。