话说 html5 之后,Web 端要及时通讯多了 SSE(Server-Sent-Event) 和 WebSocket。
SSE简单来说就是长轮询(Long-polling)的进阶版,透过javaScript API处理,只能由Server单向发送给Client。
Websocket 提供全双工、双向的资料传输,这点相当适合用在线上聊天室或游戏。
不过即时性要求不高时,又想在浏览器间兼容,长轮询(Long-polling)这种方式,还是一种选择。
网路上的比较文章很多,这里不赘述,想谈谈一个实作 Websocket 的眉角。
心跳包(HeartBeat)的重要性
在第一次握手(Handshake)后,便会建立一个长连线。而网路断线等意外,并不会呼叫 Server端的 OnClose(),导致 Server 端一厢情愿推送、苦苦等候。
透过定时/不定时确认连线状态,除了能清除占用的连线资源,也能及时处理聊天室使用者断线,比如 Client 端的断线重连,增进服务体验。
RFC 6455中定义了几种 WebSocket 资料传输单位(frame):text data、binary data、ping/pong、close等。
其中,两端都可以透过 ping/pong 来做心跳检测。
A Ping frame may serve either as a keepalive or as a means to verify that the remote endpoint is still responsive.
当Client收到一个 Ping,必须回传 Pong,告诉 Server: 他还活着。反之亦然。
Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in response, unless it already received a Close frame. It SHOULD respond with a Pong frame as soon as is practical.
注意:
WebSocket 是基于 TCP 协议,
但 TCP 的 keep-alive 机制(同样是确认状态),
无法确认当前应用层的 Application 连线可不可用。
WebSockets ping/pong, why not TCP keepalive? - Stack Overflow
在实践上,假设两端有频繁的数据互动,那透过定时的心跳检测,便会浪费传输流量。通常会记录上一次接收/发送 Websocket 讯息的时间,假设超过预设时间,才发送心跳包。
简单的做法如下:
上一篇: 聊天软体实作(2):从读写需求评估资料储存