轮询、服务器发送事件与WebSocket
輪詢
傳統輪詢
傳統輪詢借助setInterval或者setTimeout,并結合Ajax技術的方式實現。
//1
//使用setInterval,每隔10s向服務器發送一次請求。
//存在的問題是:在網絡不穩定的情況下,無法保證請求以及服務器響應的順序。
setInterval(function() {
$.getJSON("url-path")
.done(function(data) {
console.log(data);
});
}, 10000);
//2
//使用setTimeout,在每一次的請求并收到響應后,發送下一次請求。
//解決的問題:保證了每次請求的先后順序。
//存在的問題:仍然無法保證每次請求的間隔時間。
function poll() {
setTimeout(function() {
$.getJSON("url-path")
.done(function(data) {
console.log(data);
//發起下一次請求
poll();
});
}, 1000);
}
缺點分析
每次都需要新發起一條http請求。
對客戶端來說占用較多內存資源與請求資源,對服務器來說占用較多的內存資源與帶寬資源。
補充:對TCP協議三次握手的理解。
請求(含SYN標記的數據包):客戶端-->Apache/nginx服務器-->php/java/...等后端程序
響應(含SYN-ACK標記的數據包):后端程序-->Apache/nginx服務器-->客戶端
確認收到(含ACK標記的數據包):客戶端-->Apache/nginx服務器-->后端程序
長輪詢
長輪詢與下文的服務器發送事件和WebSocket都需要服務器配合。
//服務器
//通過死循環,以資源的修改時間作為循環跳出條件。
//就是上文三次握手的服務器響應階段,被后端程序的死循環“hold”住。
//當請求的服務器資源的最后一次修改時間==不舊于==客戶端請求參數所攜帶資源的時間(Last-Modified)時,跳出循環,并返回數據。
//客戶端
function longPoll(_timeStamp) {
let _timeStamp;
$.get("url-path")
.done(function(data) {
try{
let res = JSON.parse(data);
console.log(res.msg);
}catch(e) {}
})
.always(function() {
setTimeout(function() {
longPoll(_timeStamp || Date.now() / 1000);
}, 10000);
});
}
缺點:服務器資源消耗大。
解決的問題:減少了http請求。
服務器發送事件(Server-sent Event)
該方法有幾大特征如下。
HTML5規范的組成部分。
服務器到客戶端的單向通信,不需要由客戶端發起。
以“事件流”的格式產生并推送。
其格式說明如下:
MIME類型:text/event-stream
event:事件類型
data:消息內容
id:用于設置客戶端EventSource對象的“last event ID string”內部屬性
retry:指定重新連接的時間
客戶端的處理方式: 借助EventSource對象實現。
let eventSource = new EventSource("/path/to/server");
eventSource.onmessage = (e) => {
console.log(e.event, e.data);
};
//或者
eventSource.addEventListener("ping", function(e) {
console.log(e.event, e.data);
});
缺點:所有IE(包括Edge)都不支持該事件,可以通過EventSource Polyfill進行兼容處理(本質上仍然是輪詢)。
WebSocket
WebSocket有以下特征:
HTML5規范的組成部分,現在的版本是RFC6455。
實現原理較上文的幾種方式不同。
基于TCP協議。
看到這里,博客和知乎也有說基于HTTP協議的,列出網上的集合以及個人理解的集合圖。
知乎上Ovear的詳細解答:WebSocket借用HTTP協議來完成了部分握手操作。
//HTTP請求發送時,借助以下字段,通知服務器將協議切換到WebSocket。
Upgrade: websocket
Connection: Upgrade
個人的理解
繼續列舉它的特征
4. WebSocket是一個持久化的協議,相對于HTTP這種非持久的協議來說。
5. 服務器完成協議升級后,服務端可以主動推送信息給客戶端。
6. 需要socket程序實現以及額外的端口。
了解特征五之后,再思考一個問題,WebSocket與本文第二項#服務器發送事件有什么區別,與長輪詢呢?
先來看一下Websocket與長輪詢的區別。
WebSocket的流程
請求(第一次握手,同時將協議升級到WebSocket):客戶端-->Apache/nginx服務器-->后端處理程序
等待1(后端處理程序未通知信息):Apache/nginx服務器-->客戶端(保持連接狀態,使得服務器一直能夠了解客戶端的信息?)
等待2(后端處理程序通知信息):后端處理程序-->Apache/nginx服務器-->客戶端(通知客戶端更新數據)
長輪詢的流程
請求(含SYN標記的數據包):客戶端-->Apache/nginx服務器-->后端處理程序
響應(含SYN-ACK標記的數據包):后端程序“hold”住請求,待資源更新后才響應-->Apache/nginx服務器-->客戶端
確認收到(含ACK標記的數據包):客戶端-->Apache/nginx服務器-->后端程序
...重復N次
顯而易見的是,WebSocket協議免去了幾個重復的流程。有以下幾個優點:
不需要反復發送和確認http請求,免去服務器對http請求反復解析的工作。
資源未更新時,不需要通過后端代碼拖延響應的時機。WebSocket把與客戶端保持通信的任務交給了服務器,因此減少了本身處理速度就慢的程序的壓力。
與服務器發送事件的區別待補充
簡單WebSocket服務器實現代碼如下。
服務器(Node.js)
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ port: 8080 });
wss.on("connection", function(socket) {
socket.on("message", function(ms) {
console.log(msg);
socket.send("Nice to meet you!");
});
});
瀏覽器作為客戶端
//WebSocket為客戶端JavaScript的原生對象
var ws = new WebSocket("ws://localhost:8080");
ws.onopen = function(event) {
ws.send("Hello there");
}
ws.onmessage = function(event) {
console.log(event.data);
}
本文是根據參考網址學習所得的筆記和心得。
總結
以上是生活随笔為你收集整理的轮询、服务器发送事件与WebSocket的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 毛衣有什么特点
- 下一篇: 华能怎么样(华能电厂有编制吗)