如题,最近在研究IM,市面上很多的H5IM系统都有断线自动掉线重连的相关代码,测试了几套收费代码后均发现断线重连机制有各种问题,于是本着解决问题的态度,找到了如下客户端代码可以很好的解决断线重连问题;
代码依然是使用了socket长链接的心跳机制,在设定时间周期内客户端或者服务端都会自动发送心跳包,为避免带宽浪费代码会自动根据时间判断心跳方向,不废话上代码:
服务端代码:
发送心跳内容为{"type":"ping"}
,这里展示的Events.php内的部分代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/** * 当客户端发来消息时触发 * @param int $client_id 连接id * @param mixed $message 具体消息 */ public static function onMessage($client_id, $message) { $data = json_decode($message,true); if(!$data){ return; } switch ($data['type']) { case 'ping': Gateway::sendToClient($client_id, json_encode(['type'=>'pong'])); break; |
客户端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
var lockReconnect = false; //避免ws重复连接 var ws = null; // 判断当前浏览器是否支持WebSocket var wsUrl = "ws://127.0.0.1:8282"; createWebSocket(wsUrl); //连接ws function createWebSocket(url) { try { if ('WebSocket' in window) { ws = new WebSocket(url); } initEventHandle(); } catch (e) { reconnect(url); console.log(e); } } function initEventHandle() { ws.onclose = function() { reconnect(wsUrl); console.log("llws连接关闭!" + new Date().toLocaleString()); }; ws.onerror = function() { reconnect(wsUrl); console.log("llws连接错误!"); }; ws.onopen = function() { heartCheck.reset().start(); //心跳检测重置 console.log("连接成功!" + new Date().toLocaleString()); }; ws.onmessage = function(args) { //如果获取到消息,心跳检测重置 heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的 var data = JSON.parse(args.data); switch (data.type) { case 'ping': ws.send('{"type":"pong"}'); break; default: // statements_def break; } }; } // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function() { ws.close(); } function reconnect(url) { if (lockReconnect) return; lockReconnect = true; setTimeout(function() { //没连接上会一直重连,设置延迟避免请求过多 createWebSocket(url); lockReconnect = false; }, 2000); } //心跳检测 var heartCheck = { timeout: 10000, //10秒发一次心跳 timeoutObj: null, serverTimeoutObj: null, reset: function() { clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function() { var self = this; this.timeoutObj = setTimeout(function() { //这里发送一个心跳,后端收到后,返回一个心跳消息, //onmessage拿到返回的心跳就说明连接正常 ws.send('{"type":"ping"}'); self.serverTimeoutObj = setTimeout(function() { //如果超过一定时间还没重置,说明后端主动断开了 ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次 }, self.timeout) }, this.timeout) } } |
代码来源为网友提供,非原创,不喜勿喷!