摘要:而雙工通訊協(xié)議,不僅客戶端能向服務(wù)端發(fā)起請(qǐng)求,服務(wù)端也可以主動(dòng)推送信息給客戶端。目的即時(shí)通訊,替代輪詢協(xié)議在年誕生,年成為國(guó)際標(biāo)準(zhǔn)。與協(xié)議有著良好的兼容性。是一個(gè)基于的,用于實(shí)時(shí)通信的一個(gè)軟件包包括端和端,完全由實(shí)現(xiàn)。
上一篇文章簡(jiǎn)要的介紹了一下http協(xié)議,這次再介紹一下WebSocket協(xié)議,兩者之間有很大的區(qū)別,WebSocket協(xié)議是 HTML5 開(kāi)始提供的一種在單個(gè) TCP 連接上進(jìn)行全雙工通訊的協(xié)議。
簡(jiǎn)單的理解一下什么是雙工通訊協(xié)議,之前有講過(guò)http協(xié)議只能客戶端向服務(wù)端發(fā)起請(qǐng)求,是單向的應(yīng)用層協(xié)議。而雙工通訊協(xié)議,不僅客戶端能向服務(wù)端發(fā)起請(qǐng)求,服務(wù)端也可以主動(dòng)推送信息給客戶端。
目的:即時(shí)通訊,替代輪詢WebSocket 協(xié)議在2008年誕生,2011年成為國(guó)際標(biāo)準(zhǔn)。所有瀏覽器都已經(jīng)支持了。
相比于http協(xié)議,websoket協(xié)議給我們帶來(lái)了極大的方便,舉個(gè)例子:
之前,我們?cè)谧鱿⑼ㄖ臅r(shí)候,需要設(shè)置定時(shí)器,頻繁的向后臺(tái)發(fā)起異步ajax請(qǐng)求實(shí)現(xiàn)長(zhǎng)輪詢,獲取最新的數(shù)據(jù),這樣效率非常低,非常浪費(fèi)資源,因?yàn)椴煌5陌l(fā)起http請(qǐng)求,不停的與服務(wù)端建立連接,或者h(yuǎn)ttp鏈接始終打開(kāi)。
而現(xiàn)在有了websocket,就解決了輪詢的問(wèn)題,websocket只需要建立一次連接,就可以保持長(zhǎng)久連接,相比輪詢不停的建立連接,大大的提升了效率,這樣只要服務(wù)端有數(shù)據(jù)變化,就可以立即通知前臺(tái)了。
首先HTTP有 1.1 和 1.0 之說(shuō),也就是所謂的 keep-alive ,把多個(gè)HTTP請(qǐng)求合并為一個(gè),但是 Websocket 其實(shí)是一個(gè)新協(xié)議,跟HTTP協(xié)議基本沒(méi)有關(guān)系,只是為了兼容現(xiàn)有瀏覽器的握手規(guī)范而已,也就是說(shuō)它是HTTP協(xié)議上的一種補(bǔ)充,Websocket是借用了HTTP的協(xié)議來(lái)完成一部分握手。
websocket有以下特點(diǎn):
建立在 TCP 協(xié)議之上,服務(wù)器端的實(shí)現(xiàn)比較容易。
與 HTTP 協(xié)議有著良好的兼容性。默認(rèn)端口也是80和443,并且握手階段采用 HTTP 協(xié)議,因此握手時(shí)不容易屏蔽,能通過(guò)各種 HTTP
代理服務(wù)器。
屬于長(zhǎng)連接(http協(xié)議無(wú)狀態(tài))
雙向通信(http是單向通信)
可以跨域,不受瀏覽器同源策略的限制(http協(xié)議不可跨域)
數(shù)據(jù)格式比較輕量,性能開(kāi)銷小,通信高效
可以發(fā)送文本,也可以發(fā)送二進(jìn)制數(shù)據(jù)。
協(xié)議標(biāo)識(shí)符是ws(如果加密,則為wss),服務(wù)器網(wǎng)址就是 URL。如:ws://example.com:80/some/path
websocket協(xié)議應(yīng)用目前websocket對(duì)大部分瀏覽器有很好的兼容,但對(duì)于IE10以下的瀏覽器無(wú)法兼容。為了解決兼容性,Socket.IO就出現(xiàn)了。
Socket.IO是一個(gè)基于Nodejs的,用于實(shí)時(shí)通信的一個(gè)軟件包(包括client端和server端),Socket.IO完全由JavaScript實(shí)現(xiàn)。
平時(shí)在應(yīng)用的時(shí)候,可以直接引入socket.io這個(gè)庫(kù)就可以了。前后臺(tái)都需要引用該庫(kù)。
下面針對(duì)nodejs的服務(wù)端如何使用舉個(gè)例子:
服務(wù)端代碼:
const http = require("http"); const fs = require("fs"); const express = require("express"); const io = require("socket.io"); const app = express(); const httpServer = http.createServer(app); app.use("/", express.static(__dirname + "/www")); httpServer.listen(8081); const ioserve = io.listen(httpServer); let users = []; ioserve.on("connection", (socket) => { socket.on("login", (nickname) => { if (users.indexOf(nickname) > -1) { socket.emit("nickExisted"); } else { socket.userIndex = users.length; socket.nickname = nickname; users.push(nickname); socket.emit("loginSuccess"); ioserve.sockets.emit("system", nickname, users.length, "login"); } }); socket.on("postMsg", function (msg) { socket.broadcast.emit("newMsg", socket.nickname, msg); }); socket.on("img", function (imgData) { socket.broadcast.emit("newImg", socket.nickname, imgData); }) socket.on("disconnect", function () { users.splice(socket.userIndex, 1); socket.broadcast.emit("system", socket.nickname, users.length, "logout"); }); })
前臺(tái)代碼
html文件
HiChat :)
connecting to server...
js文件
; (function () { function Hichart() { this.socket = null; } Hichart.prototype = { init: function () { var that = this; this.socket = io.connect(); this.socket.on("connect", function () { document.getElementById("info").textContent = "get yourself a nickname :)"; document.getElementById("nickWrapper").style.display = "block"; document.getElementById("nicknameInput").focus(); that.login(); that.postMsg(); that.uploadImg(); }); this.socket.on("nickExisted", function () { document.getElementById("info").textContent = "!nickname is taken, choose another pls"; }); this.socket.on("loginSuccess", function () { document.title = "hichat | " + document.getElementById("nicknameInput").value; document.getElementById("loginWrapper").style.display = "none";//隱藏遮罩層顯聊天界面 document.getElementById("messageInput").focus();//讓消息輸入框獲得焦點(diǎn) }); this.socket.on("system", function (nickname, userCount, type) { var msg = nickname + (type === "login" ? " joined" : " left"); that.displayNewMsg("system ", msg, "red"); document.getElementById("status").textContent = userCount + (userCount > 1 ? " users" : " user") + " online"; }); this.socket.on("newMsg", function (nickname, msg) { that.displayNewMsg(nickname, msg); }); this.socket.on("newImg", function (nickname, newImg) { that.displayImage(nickname, newImg); }); }, login: function () { var that = this; document.getElementById("loginBtn").addEventListener("click", function () { var nickname = document.getElementById("nicknameInput").value; if (nickname.trim().length) { that.socket.emit("login", nickname); } else { document.getElementById("nicknameInput").focus(); } }, false) }, displayNewMsg: function (user, msg, color) { var container = document.getElementById("historyMsg"); var msgToDisplay = document.createElement("p"); var data = new Date().toTimeString().substr(0, 8); msgToDisplay.style.color = color || "#000"; msgToDisplay.innerHTML = user + "(" + data + "): " + msg; container.appendChild(msgToDisplay); container.scrollTop = container.scrollHeight; }, displayImage: function (user, imgData, color) { var container = document.getElementById("historyMsg"), msgToDisplay = document.createElement("p"), date = new Date().toTimeString().substr(0, 8); msgToDisplay.style.color = color || "#000"; msgToDisplay.innerHTML = user + "(" + date + "):
" + ""; container.appendChild(msgToDisplay); container.scrollTop = container.scrollHeight; }, postMsg: function () { var that = this; var sendBtn = document.getElementById("sendBtn"); var messageInput = document.getElementById("messageInput"); sendBtn.addEventListener("click", function () { var msg = messageInput.value; if (msg.trim().length != 0) { messageInput.value = ""; messageInput.focus(); that.socket.emit("postMsg", msg); that.displayNewMsg("me", msg); } }); }, uploadImg: function () { var that = this; document.getElementById("sendImage").addEventListener("change", function () { if (this.files.length) { var file = this.files[0]; var reader = new FileReader(); if (!reader) { that.displayNewMsg("system", "!your browser doesn"t support fileReader", "red"); this.value = ""; return; } reader.onload = function (e) { this.value = ""; that.socket.emit("img", e.target.result); that.displayImage("me", e.target.result); } reader.readAsDataURL(file); } }) } } window.onload = function () { var hichart = new Hichart(); hichart.init(); } })()
完整demo請(qǐng)查看我的github,地址:https://github.com/jianwenjua...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/114248.html
摘要:流控制通常就是在客戶端的頁(yè)面使用一個(gè)隱藏的窗口向服務(wù)端發(fā)出一個(gè)長(zhǎng)連接的請(qǐng)求。和長(zhǎng)鏈接以上幾種服務(wù)器推的技術(shù)中長(zhǎng)輪詢和流控制其實(shí)都是基于長(zhǎng)鏈接來(lái)實(shí)現(xiàn)的,也就是中所謂的。通信協(xié)議于年被定為標(biāo)準(zhǔn),并被所補(bǔ)充規(guī)范。 初探WebSocket node websocket socket.io 我們平常開(kāi)發(fā)的大部分web頁(yè)面都是主動(dòng)‘拉’的形式,如果需要更新頁(yè)面內(nèi)容,則需要刷新一個(gè),但Slack工...
摘要:當(dāng)數(shù)據(jù)發(fā)生變化,便將數(shù)據(jù)發(fā)送給。與網(wǎng)絡(luò)應(yīng)用中,兩個(gè)應(yīng)用程序同時(shí)需要向?qū)Ψ桨l(fā)送消息的能力即全雙工通信,所利用到的技術(shù)就是,其能夠提供端對(duì)端的通信。其不僅支持,還支持許多種輪詢機(jī)制以及其他實(shí)時(shí)通信方式,并封裝了通用的接口。 WebSocket 與 Socket.IO 最近小組在做一個(gè)智慧交通的項(xiàng)目,其中有個(gè) 分享屏幕 的功能,即一個(gè) client 能夠?qū)⒆约寒?dāng)前的頁(yè)面分享到另外一個(gè) cli...
摘要:早期的輪詢是通過(guò)不斷自動(dòng)刷新頁(yè)面而實(shí)現(xiàn)的。長(zhǎng)輪詢的另一個(gè)問(wèn)題是缺乏標(biāo)準(zhǔn)實(shí)現(xiàn)。服務(wù)器端接到這個(gè)請(qǐng)求后作出回應(yīng)并不斷更新連接狀態(tài)以保證客戶端和服務(wù)器端的連接不過(guò)期。協(xié)議解析協(xié)議包含兩部分一部分是握手,一部分是數(shù)據(jù)傳輸。 Websocket是什么? Websocket是一個(gè)因?yàn)閼?yīng)用場(chǎng)景越來(lái)越復(fù)雜而提出的,針對(duì)瀏覽器和web服務(wù)器之間雙向持續(xù)通信而設(shè)計(jì),而且優(yōu)雅地兼容HTTP的協(xié)議(我猜想:同...
摘要:服務(wù)端確認(rèn)協(xié)議版本,升級(jí)為協(xié)議。自己寫(xiě)了一個(gè)例子,服務(wù)端在開(kāi)始連接后,利用定時(shí)器主動(dòng)向客戶端發(fā)送隨機(jī)數(shù),客戶端也可以發(fā)給服務(wù)器消息,然后服務(wù)器返回這條消息給客戶端。做的事情就是給頁(yè)面的元素綁定事件。 寫(xiě)在前面webSocket是一項(xiàng)可以讓服務(wù)器將數(shù)據(jù)主動(dòng)推送給客戶端的技術(shù)。前幾天寫(xiě)了一個(gè)日志功能,日志數(shù)據(jù)需要實(shí)時(shí)更新。正好項(xiàng)目中有封裝好的WebSocket組件,且接口支持webSock...
閱讀 1837·2021-11-25 09:43
閱讀 1347·2021-11-22 15:08
閱讀 3751·2021-11-22 09:34
閱讀 3232·2021-09-04 16:40
閱讀 3034·2021-09-04 16:40
閱讀 552·2019-08-30 15:54
閱讀 1342·2019-08-29 17:19
閱讀 1759·2019-08-28 18:13