一、概述
http1.0餘http1.1支持長連接的詳解
HTTP作爲應用層協議,其實它的生命週期在服務器返回結果時就已經結束了,而所謂的支持長連接,其實是基於’Keep-Alive’請求頭所約定,從而向下進行長連接發起的一種機制。該長連接依然是基於TCP的。
因此:
所謂HTTP1.1及以上支持長連接,並不是HTTP1.1可以建立長連接,而是它支持以請求頭的方式進行長連接發起(並且要求客戶端與服務端都要具備 ‘Keep-Alive: true’ )。
再說websocket之前,我們必須知道的是什麼是半雙工通信、雙工通信、全雙工通信。
1、半雙工通信
1、同一時刻數據是單向流動的,客戶端向服務端請求數據->單向,服務端向客戶端返回數據->單向
2、服務器不能主動的推送數據給客戶端
2、雙工通信
- 長輪詢(長輪詢及是在請求的過程中,若是服務器端數據並沒有更新,那麼則將這個連接掛起,直到服務器推送新的數據,再返回,然後再進入循環週期。)
長輪詢 本質上是原始輪詢技術的一種更有效的形式。向服務器發送重複請求會浪費資源,因爲必須爲每個新傳入的請求建立連接,必須解析請求的 HTTP 頭部,必須執行對新數據的查詢,並且必鬚生成和交付響應(通常不提供新數據)。然後必須關閉連接並清除所有資源。長輪詢是一種服務器選擇儘可能長的時間保持和客戶端連接打開的技術,僅在數據變得可用或達到超時闕值後才提供響應,而不是在給到客戶端的新數據可用之前,讓每個客戶端多次發起重複的請求。
- 短輪詢(短輪詢指的是在循環週期內,不斷髮起請求,每一次請求都立即返回結果,根據新舊數據對比決定是否使用這個結果。)
- iframe流
3、全雙工通信(要知道它屬於應用層的協議,它基於TCP傳輸協議,並複用HTTP的握手通道)(在客戶端和服務端上建立了一個長久的連接,兩邊可以任意發數據)
二、我們好好聊聊websocket
1、寫一寫前端簡單的websocket
// 創建一個index.html文件
// 下面直接寫WebSocket
// 只需要new一下就可以創建一個websocket的實例
// 我們要去連接ws協議
// 這裏對應的端口就是服務端設置的端口號9999
let ws = new WebSocket('ws://localhost:9999');
// onopen是客戶端與服務端建立連接後觸發
ws.onopen = function() {
ws.send('哎呦,不錯哦');
};
// onmessage是當服務端給客戶端發來消息的時候觸發
ws.onmessage = function(res) {
console.log(res); // 打印的是MessageEvent對象
// 真正的消息數據是 res.data
console.log(res.data);
};
2、寫一寫node 的websocket
我們在用時要安裝ws包
// 創建一個index.html文件
// 下面直接寫WebSocket
// 只需要new一下就可以創建一個websocket的實例
// 我們要去連接ws協議
// 這裏對應的端口就是服務端設置的端口號9999
let ws = new WebSocket('ws://localhost:9999');
// onopen是客戶端與服務端建立連接後觸發
ws.onopen = function() {
ws.send('哎呦,不錯哦');
};
// onmessage是當服務端給客戶端發來消息的時候觸發
ws.onmessage = function(res) {
console.log(res); // 打印的是MessageEvent對象
// 真正的消息數據是 res.data
console.log(res.data);
};
3、兼容性問題的解決(socket.io)
- socket.io的特點
易用性:封裝了服務端和客戶端,使用簡單方便
跨平臺:支持跨平臺,可以選擇在服務端或是客戶端開發實時應用
自適應:會根據瀏覽器來自己決定是使用WebSocket、Ajax長輪詢還是Iframe流等方式去選擇最優方式,甚至支持IE5.5
- 安裝(npm i socket.io -S)
- 啓動服務,手寫服務端
// server.js文件
const express = require('express');
const app = express();
// 設置靜態文件夾
app.use(express.static(__dirname));
// 通過node的http模塊來創建一個server服務
const server = require('http').createServer(app);
// WebSocket是依賴HTTP協議進行握手的
const io = require('socket.io')(server);
// 監聽客戶端與服務端的連接
io.on('connection', function(socket) {
// send方法來給客戶端發消息
socket.send('青花瓷');
// 監聽客戶端的消息是否接收成功
socket.on('message', function(msg) {
console.log(msg); // 客戶端發來的消息
socket.send('天青色等煙雨,而我在等你' );
});
});
// 監聽3000端口
server.listen(3000);
- 前端代碼(在服務端運行後,客戶端就需要引用一個動態生成的文件路徑,路徑是固定的直接引用即可(/socket.io/socket.io.js))
// index.html文件
...省略
// 引用socket.io的js文件
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io('/');
// 監聽與服務器連接成功的事件
socket.on('connect', () => {
console.log('連接成功');
socket.send('周杰倫');
});
// 監聽服務端發來的消息
socket.on('message', msg => {
// 這個msg就是傳過來的真消息了,不用再msg.data取值了
console.log(`客戶端接收到的消息: ${msg}`);
});
// 監聽與服務器連接斷開事件
socket.on('disconnect', () => {
console.log('連接斷開成功');
});
</script>
其實我自己用到的socket還是比較少,就是項目中用到了websocket,然後引申了一下,如果有時間會好好整理一下socket.io,
若有不正確的地方,請聯繫我改正,謝謝!