网站首页 > 技术文章 正文
传统轮询(Traditional Polling)
当前Web应用中较常见的一种持续通信方式,通常采取 setInterval 或者 setTimeout 实现。例如如果我们想要定时获取并刷新页面上的数据,可以结合Ajax写出如下实现:
setInterval(function() { $.get("/path/to/server", function(data, status) { console.log(data); }); }, 10000);复制代码
上面的程序会每隔10秒向服务器请求一次数据,并在数据到达后存储。这个实现方法通常可以满足简单的需求,然而同时也存在着很大的缺陷:在网络情况不稳定的情况下,服务器从接收请求、发送请求到客户端接收请求的总时间有可能超过10秒,而请求是以10秒间隔发送的,这样会导致接收的数据到达先后顺序与发送顺序不一致。于是出现了采用 setTimeout 的轮询方式:
function poll() { setTimeout(function() { $.get("/path/to/server", function(data, status) { console.log(data); // 发起下一次请求 poll(); }); }, 10000); }复制代码
程序首先设置10秒后发起请求,当数据返回后再隔10秒发起第二次请求,以此类推。这样的话虽然无法保证两次请求之间的时间间隔为固定值,但是可以保证到达数据的顺序。
缺陷
程序在每次请求时都会新建一个HTTP请求,然而并不是每次都能返回所需的新数据。当同时发起的请求达到一定数目时,会对服务器造成较大负担。
长轮询(long poll)
客户端发送一个request后,服务器拿到这个连接,如果有消息,才返回response给客户端。没有消息,就一直不返回response。之后客户端再次发送request, 重复上次的动作。
总结
http协议的特点是服务器不能主动联系客户端,只能由客户端发起。它的被动性预示了在完成双向通信时需要不停的连接或连接一直打开,这就需要服务器快速的处理速度或高并发的能力,是非常消耗资源的。
什么是websocket?
websocket是HTML5的一个新协议,它允许服务端向客户端传递信息,实现浏览器和客户端双工通信
故事
因为 HTTP 协议有一个缺陷:通信只能由客户端发起。 举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。
websocket的特点
服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
- 与 HTTP 协议有着良好的兼容性。默认端口也是 80 和 443 ,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 建立在TCP协议基础之上,和http协议同属于应用层
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信
- 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL,如ws://localhost:8023
跨平台的WebSocket通信库socket.io
跨平台的WebSocket通信库,具有前后端一致的API,可以触发和响应自定义的事件。socket.io最核心的两个api就是emit 和 on了 ,服务端和客户端都有这两个api。通过 emit 和 on可以实现服务器与客户端之间的双向通信。
- emit :发射一个事件,第一个参数为事件名,第二个参数为要发送的数据,第三个参数为回调函数(如需对方接受到信息后立即得到确认时,则需要用到回调函数)。
- on :监听一个 emit 发射的事件,第一个参数为要监听的事件名,第二个参数为回调函数,用来接收对方发来的数据,该函数的第一个参数为接收的数据。
服务端
var app = require('express')(); var http = require('http'); var socketio = require("socket.io"); const server = http.createServer(app) const io = socketio(server) var count = 0; // WebSocket 连接服务器 io.on('connection', (socket)=> { //// 所有的事件触发响应都写在这里 setInterval(()=>{ count++ //向建立该连接的客户端发送消息 socket.emit('mynameEv', { name:"你我贷"+count}) },1000) //监听客户端发送信息 socket.on('yournameEv', function (data) { console.log(data) }) }) app.get('/', function (req, res) { res.sendfile(__dirname + '/index.html'); }); // 启用3000端口 server.listen(3000)复制代码
客户端
<body> <div id="myname"></div> <script src="http://localhost:3000/socket.io/socket.io.js"></script> <script> var count = 0; const socket = io.connect('http://localhost:3000') socket.on('mynameEv', (data)=>{ document.getElementById("myname").innerHTML = data.name; console.log(data.name) setInterval(()=>{ count++ socket.emit('yournameEv', { name:"飞旋"+count}) },1000) }) </script> </body>复制代码
当然 有了连接 通讯 还有一种掉线的情况,那么掉线情况下 如何进行通讯 连接呢?
心跳检测
心跳检测步骤:
1客户端每隔一个时间间隔发生一个探测包给服务器
2客户端发包时启动一个超时定时器
3服务器端接收到检测包,应该回应一个包
4如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器
5如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了
前端解决方案:
var heartCheck = { timeout: 30000, //30秒发一次心跳 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("ping"); console.log("ping!") self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了 ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次 }, self.timeout) }, this.timeout) } }
断线的可能原因2:
websocket异常包括服务端出现中断,交互切屏等等客户端异常中断等等
针对这种异常的中断解决方案就是处理重连,下面我们给出的重连方案是使用js库处理:
引入reconnecting-websocket.min.js,ws建立链接方法使用js库api方法:
var ws = new ReconnectingWebSocket(url); 断线重连: reconnectSocket(){ if ('ws' in window) { ws = new ReconnectingWebSocket(url); } else if ('MozWebSocket' in window) { ws = new MozWebSocket(url); } else { ws = new SockJS(url); } }
在websocket断开链接时调用网络中断监测
websocket.onclose => () { onLineCheck(); };
链接:https://juejin.im/post/5cacb459f265da03a00fb2fe
来源:掘金
猜你喜欢
- 2024-10-13 websocket-sharp:.NET平台上的WebSocket客户端与服务器开源库
- 2024-10-13 dart系列之:实时通讯,在浏览器中使用WebSockets
- 2024-10-13 WebSocket菜鸟教程二(websocketpp教程)
- 2024-10-13 建立一个加密货币的教程(一)(制作加密货币)
- 2024-10-13 WebSocket 对象简介(websocket相关技术)
- 2024-10-13 netty系列之:使用netty搭建websocket客户端
- 2024-10-13 聊聊分布式下的WebSocket解决方案
- 2024-10-13 OkHttp 实现 WebSocket 真的太好用了,聊聊长连接如何保活
- 2024-10-13 WebSocket基础讲解(1)(websocketclient)
- 2024-10-13 利用WebSocket跨站劫持(CSWH)漏洞接管帐户
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)