websocket的定義
WebSocket是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議每辟。WebSocket通信協(xié)議于2011年被IETF定為標(biāo)準(zhǔn)RFC 6455瞳步,并由RFC7936補(bǔ)充規(guī)范黎做。WebSocket API也被W3C定為標(biāo)準(zhǔn)伐债。
WebSocket使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單嫁艇,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù)攀芯。在WebSocket API中附鸽,瀏覽器和服務(wù)器只需要完成一次握手脱拼,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸坷备。
websocket的優(yōu)勢(shì):
- 較少的控制開銷熄浓。
- 更強(qiáng)的實(shí)時(shí)性。由于協(xié)議是全雙工的省撑,所以服務(wù)器可以隨時(shí)主動(dòng)給客戶端下發(fā)數(shù)據(jù)赌蔑。相對(duì)于HTTP請(qǐng)求需要等待客戶端發(fā)起請(qǐng)求服務(wù)端才能響應(yīng),延遲明顯更少竟秫;即使是和Comet等類似的長(zhǎng)輪詢比較娃惯,其也能在短時(shí)間內(nèi)更多次地傳遞數(shù)據(jù)。
- 保持連接狀態(tài)肥败。與HTTP不同的是趾浅,Websocket需要先創(chuàng)建連接愕提,這就使得其成為一種有狀態(tài)的協(xié)議,之后通信時(shí)可以省略部分狀態(tài)信息皿哨。而HTTP請(qǐng)求可能需要在每個(gè)請(qǐng)求都攜帶狀態(tài)信息(如身份認(rèn)證等)浅侨。
更好的二進(jìn)制支持。Websocket定義了二進(jìn)制幀证膨,相對(duì)HTTP如输,可以更輕松地處理二進(jìn)制內(nèi)容。 - 可以支持?jǐn)U展央勒。Websocket定義了擴(kuò)展不见,用戶可以擴(kuò)展協(xié)議、實(shí)現(xiàn)部分自定義的子協(xié)議崔步。如部分瀏覽器支持壓縮等脖祈。
- 更好的壓縮效果。相對(duì)于HTTP壓縮刷晋,Websocket在適當(dāng)?shù)臄U(kuò)展支持下盖高,可以沿用之前內(nèi)容的上下文,在傳遞類似的數(shù)據(jù)時(shí)眼虱,可以顯著地提高壓縮率喻奥。
使用socket.io實(shí)現(xiàn)簡(jiǎn)單的聊天室
- 前端代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>websocket聊天室</title>
<style>
#content{
width: 600px;
height: 300px;
border: 1px solid black;
}
.me{
color: green;
}
</style>
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
<script>
let sock = io.connect("ws://localhost:8080");
sock.on("connect",()=>{
console.log("連接建立");
})
sock.on("disconnect",()=>{
console.log("連接斷開");
})
window.onload = function(){
let ul = document.querySelector("#content");
let msg = document.querySelector("#msg");
let btn = document.querySelector("#btn");
sock.on("msg",function(str){
let li = document.createElement("li");
li.innerHTML = str;
ul.appendChild(li);
})
btn.onclick = function(){
let sendMsg = msg.value.replace(/(^\s+)|(\s+$)/g,"");
if(sendMsg.length !== 0){
sock.emit("msg",sendMsg);
let li = document.createElement("li");
li.innerHTML= sendMsg;
li.className = "me";
ul.appendChild(li);
msg.value = "";
}
}
}
</script>
</head>
<body>
<ul id="content"></ul>
<textarea id="msg" cols="80" rows="10"></textarea>
<input type="submit" value="發(fā)送" id="btn">
</body>
</html>
- nodejs服務(wù)器端的代碼
const http = require("http");
const io = require("socket.io");
let httpServer = http.createServer();
httpServer.listen(8080);
let wsServer = io.listen(httpServer);
let sockArr = [];
wsServer.on("connection",sock=>{
sockArr.push(sock);
sock.on("disconnect",()=>{
let n = sockArr.indexOf(sock);
if(n!=-1){
sockArr.splice(n,1);
}
})
sock.on("msg",function(str){
sockArr.forEach(s=>{
if(s!=sock){
s.emit("msg",str);
}
})
})
setInterval(() => {
console.log(sockArr.length)
}, 1000);
})