默認
打賞 發表評論 12
想開發IM:買成品怕坑?租第3方怕貴?找開源自已擼?盡量別走彎路了... 找站長給點建議
WebSocket詳解(一):初步認識WebSocket技術
閱讀(129038) | 評論(12 收藏25 淘帖1 10

1、前言


HTML5規范在傳統的web交互基礎上為我們帶來了眾多的新特性,隨著web技術被廣泛用于web APP的開發,這些新特性得以推廣和使用,而websocket作為一種新的web通信技術具有巨大意義。

本文將帶您認識WebSocket。也可查看本文的下篇:《WebSocket詳解(二):技術原理、代碼演示和應用案例》。

2、系列文章


本文是系列文章中的第1篇,本系列文章的大綱如下:


3、更多資料


Web端即時通訊新手入門貼:
新手入門貼:詳解Web端即時通訊技術的原理

Web端即時通訊技術盤點請參見:
Web端即時通訊技術盤點:短輪詢、Comet、Websocket、SSE

關于Ajax短輪詢:
找這方面的資料沒什么意義,除非忽悠客戶,否則請考慮其它3種方案即可。

有關Comet技術的詳細介紹請參見:
Comet技術詳解:基于HTTP長連接的Web端實時通信技術
WEB端即時通訊:HTTP長連接、長輪詢(long polling)詳解
WEB端即時通訊:不用WebSocket也一樣能搞定消息的即時性
開源Comet服務器iComet:支持百萬并發的Web端即時通訊方案

更多WebSocket的詳細介紹請參見:
新手快速入門:WebSocket簡明教程
理論聯系實際:從零理解WebSocket的通信原理、協議格式、安全性
八問WebSocket協議:為你快速解答WebSocket熱門疑問
Socket.IO介紹:支持WebSocket、用于WEB端的即時通訊的框架
socket.io和websocket 之間是什么關系?有什么區別?

有關SSE的詳細介紹文章請參見:
SSE技術詳解:一種全新的HTML5服務器推送事件技術

更多WEB端即時通訊文章請見:
http://www.emxvra.tw/forum.php?mod=collection&action=view&ctid=15

4、什么是Socket?什么是WebSocket?


對于第1次聽說WebSocket技術的人來說,兩者有什么區別?websocket是僅僅將socket的概念移植到瀏覽器中的實現嗎?

我們知道,在網絡中的兩個應用程序(進程)需要全雙工相互通信(全雙工即雙方可同時向對方發送消息),需要用到的就是socket,它能夠提供端對端通信,對于程序員來講,他只需要在某個應用程序的一端(暫且稱之為客戶端)創建一個socket實例并且提供它所要連接一端(暫且稱之為服務端)的IP地址和端口,而另外一端(服務端)創建另一個socket并綁定本地端口進行監聽,然后客戶端進行連接服務端,服務端接受連接之后雙方建立了一個端對端的TCP連接,在該連接上就可以雙向通訊了,而且一旦建立這個連接之后,通信雙方就沒有客戶端服務端之分了,提供的就是端對端通信了。我們可以采取這種方式構建一個桌面版的im程序,讓不同主機上的用戶發送消息。從本質上來說,socket并不是一個新的協議,它只是為了便于程序員進行網絡編程而對tcp/ip協議族通信機制的一種封裝。

websocket是html5規范中的一個部分,它借鑒了socket這種思想,為web應用程序客戶端和服務端之間(注意是客戶端服務端)提供了一種全雙工通信機制。同時,它又是一種新的應用層協議,websocket協議是為了提供web應用程序和服務端全雙工通信而專門制定的一種應用層協議,通常它表示為:ws://echo.websocket.org/?encoding=text HTTP/1.1,可以看到除了前面的協議名和http不同之外,它的表示地址就是傳統的url地址。

可以看到,websocket并不是簡單地將socket這一概念在瀏覽器環境中的移植,本文最后也會通過一個小的demo來進一步講述socket和websocket在使用上的區別。

5、WebSocket的通信原理和機制


既然是基于瀏覽器端的web技術,那么它的通信肯定少不了http,websocket本身雖然也是一種新的應用層協議,但是它也不能夠脫離http而單獨存在。具體來講,我們在客戶端構建一個websocket實例,并且為它綁定一個需要連接到的服務器地址,當客戶端連接服務端的時候,會向服務端發送一個類似下面的http報文:

WebSocket詳解(一):初步認識WebSocket技術_1.png

可以看到,這是一個http get請求報文,注意該報文中有一個upgrade首部,它的作用是告訴服務端需要將通信協議切換到websocket,如果服務端支持websocket協議,那么它就會將自己的通信協議切換到websocket,同時發給客戶端類似于以下的一個響應報文頭:

WebSocket詳解(一):初步認識WebSocket技術_2.png

返回的狀態碼為101,表示同意客戶端協議轉換請求,并將它轉換為websocket協議。以上過程都是利用http通信完成的,稱之為websocket協議握手(websocket Protocol handshake),進過這握手之后,客戶端和服務端就建立了websocket連接,以后的通信走的都是websocket協議了。所以總結為websocket握手需要借助于http協議,建立連接后通信過程使用websocket協議。同時需要了解的是,該websocket連接還是基于我們剛才發起http連接的那個TCP連接。一旦建立連接之后,我們就可以進行數據傳輸了,websocket提供兩種數據傳輸:文本數據和二進制數據。

基于以上分析,我們可以看到,websocket能夠提供低延遲,高性能的客戶端與服務端的雙向數據通信。它顛覆了之前web開發的請求處理響應模式,并且提供了一種真正意義上的客戶端請求,服務器推送數據的模式,特別適合實時數據交互應用開發。

6、WebSocket技術出現之前,Web端實現即時通訊的方法有哪些?


6.1定期輪詢的方式


客戶端按照某個時間間隔不斷地向服務端發送請求,請求服務端的最新數據然后更新客戶端顯示。這種方式實際上浪費了大量流量并且對服務端造成了很大壓力。

6.2SSE(Server-Sent Event,服務端推送事件)


SSE(Server-Sent Event,服務端推送事件)是一種允許服務端向客戶端推送新數據的HTML5技術。與由客戶端每隔幾秒從服務端輪詢拉取新數據相比,這是一種更優的解決方案。

相較于WebSocket,它也能從服務端向客戶端推送數據。WebSocket能做的,SSE也能做,反之亦然,但在完成某些任務方面,它們各有千秋。關于SSE的介紹,即時通訊網將在稍后的文章中詳細介紹。

6.3Comet技術


Comet并不是一種新的通信技術,它是在客戶端請求服務端這個模式上的一種hack技術,通常來講,它主要分為以下兩種做法:

(1)基于長輪詢的服務端推送技術
具體來講,就是客戶端首先給服務端發送一個請求,服務端收到該請求之后如果數據沒有更新則并不立即返回,服務端阻塞請求的返回,直到數據發生了更新或者發生了連接超時,服務端返回數據之后客戶端再次發送同樣的請求,如下所示:
WebSocket詳解(一):初步認識WebSocket技術_a.png

(2)基于流式數據傳輸的長連接
通常的做法是在頁面中嵌入一個隱藏的iframe,然后讓這個iframe的src屬性指向我們請求的一個服務端地址,并且為了數據更新,我們將頁面上數據更新操作封裝為一個js函數,將函數名當做參數傳遞到這個地址當中。

服務端收到請求后解析地址取出參數(客戶端js函數調用名),每當有數據更新的時候,返回對客戶端函數的調用,并且將要跟新的數據以js函數的參數填入到返回內容當中,例如返回“<script type="text/javascript">update("data")</script>”這樣一個字符串,意味著以data為參數調用客戶端update函數進行客戶端view更新。基本模型如下所示:
WebSocket詳解(一):初步認識WebSocket技術_b.png

可以看到comet技術是針對客戶端請求服務器響應模型而模擬出的一個服務端推送數據實時更新技術。而且由于瀏覽器兼容性不能夠廣泛應用。

6.4小結


當然并不是說這些技術沒有用,就算websocket已經作為規范被提出并實現,但是對于老式瀏覽器,我們依然需要將它降級為以上方式來實現實時交互和服務端數據推送。

7、一個簡單的WebSocket聊天小例子


到此為止,我們明白了websocket的原理,下面通過一個簡單的聊天應用來再次加深下對websocket的理解。該應用需求很簡單,就是在web選項卡中打開兩個網頁,模擬兩個web客戶端實現聊天功能。

7.1客戶端代碼


client.html:
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .message{
            width: 60%;
            margin: 0 10px;
            display: inline-block;
            text-align: center;
            height: 40px;
            line-height: 40px;
            font-size: 20px;
            border-radius: 5px;
            border: 1px solid #B3D33F;
        }
        .form{
            width:100%;
            position: fixed;
            bottom: 300px;
            left: 0;
        }
        .connect{
            height: 40px;
            vertical-align: top;
            /* padding: 0; */
            width: 80px;
            font-size: 20px;
            border-radius: 5px;
            border: none;
            background: #B3D33F;
            color: #fff;
        }
    </style>
</head>
<body>
<ul id="content"></ul>
<form class="form">
<input type="text" placeholder="請輸入發送的消息" class="message" id="message"/>
<input type="button" value="發送" id="send" class="connect"/>
<input type="button" value="連接" id="connect" class="connect"/>
</form>
<script></script>
</body>
</html>

客戶端js代碼:
var oUl=document.getElementById('content');
    var oConnect=document.getElementById('connect');
    var oSend=document.getElementById('send');
    var oInput=document.getElementById('message');
    var ws=null;
    oConnect.onclick=function(){
        ws=new WebSocket('ws://localhost:5000');
         ws.onopen=function(){
             oUl.innerHTML+="<li>客戶端已連接</li>";
         }
        ws.onmessage=function(evt){
            oUl.innerHTML+="<li>"+evt.data+"</li>";
        }
        ws.onclose=function(){
            oUl.innerHTML+="<li>客戶端已斷開連接</li>";
        };
        ws.onerror=function(evt){
            oUl.innerHTML+="<li>"+evt.data+"</li>";

        };
    };
    oSend.onclick=function(){
        if(ws){
            ws.send(oInput.value);
        }
    }

這里使用的是w3c規范中關于HTML5 websocket API的原生API,這些api很簡單,就是利用new WebSocket創建一個指定連接服務端地址的ws實例,然后為該實例注冊onopen(連接服務端),onmessage(接受服務端數據),onclose(關閉連接)以及ws.send(建立連接后)發送請求。上面說了那么多,事實上可以看到html5 websocket API本身是很簡單的一個對象和它的幾個方法而已。

7.2服務端代碼


服務端采用Node.js,這里需要基于一個nodejs-websocket的Node.js服務端的庫,它是一個輕量級的Node.js websocket server端的實現,實際上也是使用Node.js提供的net模塊寫成的。

server.js:
var app=require('http').createServer(handler);
var ws=require('nodejs-websocket');
var fs=require('fs');
app.listen(80);
function handler(req,res){
    fs.readFile(__dirname+'/client.html',function(err,data){
        if(err){
            res.writeHead(500);
            return res.end('error ');
        }
        res.writeHead(200);
        res.end(data);
    });
}
var server=ws.createServer(function(conn){
    console.log('new conneciton');
    conn.on("text",function(str){
        broadcast(server,str);
    });
    conn.on("close",function(code,reason){
        console.log('connection closed');
    })
}).listen(5000);

function broadcast(server, msg) {
    server.connections.forEach(function (conn) {
        conn.sendText(msg);
    })
}

首先利用http模塊監聽用戶的http請求并顯示client.html界面,然后創建一個websocket服務端等待用戶連接,在接收到用戶發送來的數據之后將它廣播到所有連接到的客戶端。

7.3運行


下面我們打開兩個瀏覽器選項卡模擬兩個客戶端進行連接。

客戶端一發起連接:
WebSocket詳解(一):初步認識WebSocket技術_x1.png

客戶端一請求響應報文如下:
WebSocket詳解(一):初步認識WebSocket技術_x2.png

可以看到這次握手和我們之前講的如出一轍。

客戶端二的連接過程和1是一樣的,這里為了查看我們使用ff瀏覽器,兩個客戶端的連接情況如下:
WebSocket詳解(一):初步認識WebSocket技術_x3.jpg

發送消息情況如下:
WebSocket詳解(一):初步認識WebSocket技術_x4.png

可以看到,雙方發送的消息被服務端廣播給了每個和自己連接的客戶端。

8、結語


從上面的即時通訊聊天例子我們可以看到,要想做一個點對點的im應用,websocket采取的方式是讓所有客戶端連接服務端,服務器將不同客戶端發送給自己的消息進行轉發或者廣播,而對于原始的socket,只要兩端建立連接之后,就可以發送端對端的數據,不需要經過第三方的轉發(即時通訊網注:原文作者指的是原生的Socket可以通過P2P直接進行消息交互,實際現今主流的IM應用幾乎都是使用服務端中轉的方式進行文本類消息的發送,使用中轉無關技術,主要是基于運營考慮),這也是websocket不同于socket的一個重要特點。

最后,本文為了說明html5規范中的websocket在客戶端采用了websocket原生的API,實際開發中,有比較著名的兩個庫socket.io和sockjs,它們都對原始的websocket API做了進一步封裝,提供了更多功能,都分為客戶端和服務端的實現,實際應用中,可以選擇使用。

如果您覺得本文還是顯得有點專業,可以看看知乎上的這篇《WebSocket 是什么原理?為什么可以實現持久連接?》,比較通俗,適合快餐式地了解WebSocket。

附錄:全站即時通訊技術資料分類


[1] 網絡編程基礎資料:
TCP/IP詳解 - 第11章·UDP:用戶數據報協議
TCP/IP詳解 - 第17章·TCP:傳輸控制協議
TCP/IP詳解 - 第18章·TCP連接的建立與終止
TCP/IP詳解 - 第21章·TCP的超時與重傳
理論經典:TCP協議的3次握手與4次揮手過程詳解
理論聯系實際:Wireshark抓包分析TCP 3次握手、4次揮手過程
計算機網絡通訊協議關系圖(中文珍藏版)
NAT詳解:基本原理、穿越技術(P2P打洞)、端口老化等
UDP中一個包的大小最大能多大?
Java新一代網絡編程模型AIO原理及Linux系統AIO介紹
NIO框架入門(三):iOS與MINA2、Netty4的跨平臺UDP雙向通信實戰
NIO框架入門(四):Android與MINA2、Netty4的跨平臺UDP雙向通信實戰
>> 更多同類文章 ……

[2] 有關IM/推送的通信格式、協議的選擇:
為什么QQ用的是UDP協議而不是TCP協議?
移動端即時通訊協議選擇:UDP還是TCP?
如何選擇即時通訊應用的數據傳輸格式
強列建議將Protobuf作為你的即時通訊應用數據傳輸格式
移動端IM開發需要面對的技術問題(含通信協議選擇)
簡述移動端IM開發的那些坑:架構設計、通信協議和客戶端
理論聯系實際:一套典型的IM通信協議設計詳解
58到家實時消息系統的協議設計等技術實踐分享
>> 更多同類文章 ……

[3] 有關IM/推送的心跳保活處理:
Android進程保活詳解:一篇文章解決你的所有疑問
Android端消息推送總結:實現原理、心跳保活、遇到的問題等
為何基于TCP協議的移動端IM仍然需要心跳保活機制?
微信團隊原創分享:Android版微信后臺保活實戰分享(進程保活篇)
微信團隊原創分享:Android版微信后臺保活實戰分享(網絡保活篇)
移動端IM實踐:實現Android版微信的智能心跳機制
移動端IM實踐:WhatsApp、Line、微信的心跳策略分析
>> 更多同類文章 ……

[4] 有關WEB端即時通訊開發:
新手入門貼:史上最全Web端即時通訊技術原理詳解
Web端即時通訊技術盤點:短輪詢、Comet、Websocket、SSE
SSE技術詳解:一種全新的HTML5服務器推送事件技術
Comet技術詳解:基于HTTP長連接的Web端實時通信技術
WebSocket詳解(一):初步認識WebSocket技術
socket.io實現消息推送的一點實踐及思路
>> 更多同類文章 ……

[5] 有關IM架構設計:
淺談IM系統的架構設計
簡述移動端IM開發的那些坑:架構設計、通信協議和客戶端
一套原創分布式即時通訊(IM)系統理論架構方案
從零到卓越:京東客服即時通訊系統的技術架構演進歷程
蘑菇街即時通訊/IM服務器開發之架構選擇
騰訊QQ1.4億在線用戶的技術挑戰和架構演進之路PPT
微信技術總監談架構:微信之道——大道至簡(演講全文)
如何解讀《微信技術總監談架構:微信之道——大道至簡》
快速裂變:見證微信強大后臺架構從0到1的演進歷程(一)
17年的實踐:騰訊海量產品的技術方法論
>> 更多同類文章 ……

[6] 有關IM安全的文章:
即時通訊安全篇(一):正確地理解和使用Android端加密算法
即時通訊安全篇(二):探討組合加密算法在IM中的應用
即時通訊安全篇(三):常用加解密算法與通訊安全講解
即時通訊安全篇(四):實例分析Android中密鑰硬編碼的風險
傳輸層安全協議SSL/TLS的Java平臺實現簡介和Demo演示
理論聯系實際:一套典型的IM通信協議設計詳解(含安全層設計)
微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解
來自阿里OpenIM:打造安全可靠即時通訊服務的技術實踐分享
>> 更多同類文章 ……

[7] 有關實時音視頻開發:
即時通訊音視頻開發(一):視頻編解碼之理論概述
即時通訊音視頻開發(二):視頻編解碼之數字視頻介紹
即時通訊音視頻開發(三):視頻編解碼之編碼基礎
即時通訊音視頻開發(四):視頻編解碼之預測技術介紹
即時通訊音視頻開發(五):認識主流視頻編碼技術H.264
即時通訊音視頻開發(六):如何開始音頻編解碼技術的學習
即時通訊音視頻開發(七):音頻基礎及編碼原理入門
即時通訊音視頻開發(八):常見的實時語音通訊編碼標準
即時通訊音視頻開發(九):實時語音通訊的回音及回音消除概述
即時通訊音視頻開發(十):實時語音通訊的回音消除技術詳解
即時通訊音視頻開發(十一):實時語音通訊丟包補償技術詳解
即時通訊音視頻開發(十二):多人實時音視頻聊天架構探討
即時通訊音視頻開發(十三):實時視頻編碼H.264的特點與優勢
即時通訊音視頻開發(十四):實時音視頻數據傳輸協議介紹
即時通訊音視頻開發(十五):聊聊P2P與實時音視頻的應用情況
即時通訊音視頻開發(十六):移動端實時音視頻開發的幾個建議
即時通訊音視頻開發(十七):視頻編碼H.264、V8的前世今生
簡述開源實時音視頻技術WebRTC的優缺點
良心分享:WebRTC 零基礎開發者教程(中文)
>> 更多同類文章 ……

[8] IM開發綜合文章:
移動端IM開發需要面對的技術問題
開發IM是自己設計協議用字節流好還是字符流好?
請問有人知道語音留言聊天的主流實現方式嗎?
IM系統中如何保證消息的可靠投遞(即QoS機制)
談談移動端 IM 開發中登錄請求的優化
完全自已開發的IM該如何設計“失敗重試”機制?
微信對網絡影響的技術試驗及分析(論文全文)
即時通訊系統的原理、技術和應用(技術論文)
開源IM工程“蘑菇街TeamTalk”的現狀:一場有始無終的開源秀
>> 更多同類文章 ……

[9] 開源移動端IM技術框架資料:
開源移動端IM技術框架MobileIMSDK:快速入門
開源移動端IM技術框架MobileIMSDK:常見問題解答
開源移動端IM技術框架MobileIMSDK:壓力測試報告
開源移動端IM技術框架MobileIMSDK:Android版Demo使用幫助
開源移動端IM技術框架MobileIMSDK:Java版Demo使用幫助
開源移動端IM技術框架MobileIMSDK:iOS版Demo使用幫助
開源移動端IM技術框架MobileIMSDK:Android客戶端開發指南
開源移動端IM技術框架MobileIMSDK:Java客戶端開發指南
開源移動端IM技術框架MobileIMSDK:iOS客戶端開發指南
開源移動端IM技術框架MobileIMSDK:Server端開發指南
>> 更多同類文章 ……

[10] 有關推送技術的文章:
iOS的推送服務APNs詳解:設計思路、技術原理及缺陷等
Android端消息推送總結:實現原理、心跳保活、遇到的問題等
掃盲貼:認識MQTT通信協議
一個基于MQTT通信協議的完整Android推送Demo
求教android消息推送:GCM、XMPP、MQTT三種方案的優劣
移動端實時消息推送技術淺析
掃盲貼:淺談iOS和Android后臺實時消息推送的原理和區別
絕對干貨:基于Netty實現海量接入的推送服務技術要點
移動端IM實踐:谷歌消息推送服務(GCM)研究(來自微信)
為何微信、QQ這樣的IM工具不使用GCM服務推送消息?
>> 更多同類文章 ……

[11] 更多即時通訊技術好文分類:
http://www.emxvra.tw/forum.php?mod=collection&op=all

(原文鏈接:http://www.cnblogs.com/myzhibie/p/4470065.html,原文有改動)

即時通訊網 - 即時通訊開發者社區! 來源: - 即時通訊開發者社區!

本帖已收錄至以下技術專輯

推薦方案
評論 12
掃盲貼,通谷易懂,頂一個!
簽名: 好久沒來了,簽個到
感謝樓主分享
怎么評論這么少
簡單易懂,很透徹
樓主是個好人
樓主好人啊!
websocket剛入門,這篇文件講解的和明了
您好,你的那個基于node.js的庫是什么意思
如何基于他的node.js庫,具體怎么操作
引用:哈盛世三國 發表于 2017-12-29 16:55
如何基于他的node.js庫,具體怎么操作

你指的是MobileIMSDK-Web框架嗎?
簽名: 又是精神萎靡的一天,真美好。。
感謝,感謝
學習了
打賞樓主 ×
使用微信打賞! 使用支付寶打賞!

返回頂部
777彩票走势图表