MST

星途 面试题库

面试题:网络编程之WebSocket心跳机制实现

在基于WebSocket的在线协作平台中,为了保持连接的活性,需要实现心跳机制。请阐述如何设计并实现WebSocket的心跳机制,包括心跳消息的格式、发送频率以及如何处理心跳超时情况。
46.1万 热度难度
后端开发网络编程

知识考点

AI 面试

面试题答案

一键面试

心跳消息格式

可以设计一个简单的JSON格式消息,例如:

{
    "type": "heartbeat",
    "timestamp": "当前时间戳"
}

type字段表明这是心跳消息,timestamp用于服务端判断消息顺序及是否有消息丢失。

发送频率

发送频率需要根据实际场景来设定。一般来说,如果网络环境较好且对实时性要求不是极高,可以设置为30秒到1分钟发送一次心跳消息。如果网络波动较大或者对实时连接状态要求非常严格,可能需要缩短到10 - 20秒发送一次。

处理心跳超时情况

  1. 客户端处理
    • 客户端发送心跳消息后,启动一个定时器。如果在设定时间(例如比发送频率略长,如发送频率为30秒,超时时间设为40秒)内没有收到服务端的心跳响应,客户端可以尝试重新连接WebSocket。
    • 代码示例(JavaScript):
const socket = new WebSocket('ws://your - server - url');
let heartbeatTimer;
function sendHeartbeat() {
    const heartbeat = {
        type: 'heartbeat',
        timestamp: new Date().getTime()
    };
    socket.send(JSON.stringify(heartbeat));
    heartbeatTimer = setTimeout(() => {
        console.log('Heartbeat timeout, attempting to reconnect...');
        socket.close();
        // 尝试重新连接
        socket.open('ws://your - server - url');
    }, 40000);
}
socket.addEventListener('open', () => {
    sendHeartbeat();
});
socket.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    if (data.type === 'heartbeat - response') {
        clearTimeout(heartbeatTimer);
        sendHeartbeat();
    }
});
  1. 服务端处理
    • 服务端收到心跳消息后,记录客户端的活跃时间。如果在一定时间(同样比心跳发送频率略长)内没有收到某个客户端的心跳消息,服务端可以主动关闭与该客户端的连接。
    • 以Python的Tornado框架为例:
import tornado.ioloop
import tornado.web
import tornado.websocket
import time

class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        self.last_heartbeat_time = time.time()
        tornado.ioloop.IOLoop.current().call_later(60, self.check_heartbeat)

    def on_message(self, message):
        data = json.loads(message)
        if data['type'] == 'heartbeat':
            self.last_heartbeat_time = time.time()
            response = {
                'type': 'heartbeat - response',
                'timestamp': time.time()
            }
            self.write_message(json.dumps(response))

    def check_heartbeat(self):
        if time.time() - self.last_heartbeat_time > 50:
            self.close()
        else:
            tornado.ioloop.IOLoop.current().call_later(60, self.check_heartbeat)