Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 506, comments - 13, trackbacks - 0, articles - 1

          一、引言

          WebSocket是一種比較新的協(xié)議,它是伴隨著html5規(guī)范而生的,雖然還比較年輕,但大多主流瀏覽器都已經(jīng)支持。它使用方面、應(yīng)用廣泛,已經(jīng)滲透到前后端開發(fā)的各種場景中。

          對(duì)http一問一答中二式流程(就是從所周之的“長輪詢”技要啦)的不滿,催生了支持雙向通信的WebSocket誕生。WebSocket是個(gè)不太干凈協(xié)議。

          本文將從8個(gè)常見的疑問入手,為還不了解WebSocket協(xié)議的開發(fā)者快速普及相關(guān)知識(shí),從而節(jié)省您學(xué)習(xí)WebSocket的時(shí)間。

          另外,如果您對(duì)Web端的即時(shí)通訊技術(shù)還完全不了解,那么《新手入門貼:詳解Web端即時(shí)通訊技術(shù)的原理》、《Web端即時(shí)通訊技術(shù)盤點(diǎn):短輪詢、Comet、Websocket、SSE》這兩篇文章請(qǐng)您務(wù)必抽時(shí)間讀一讀。

          學(xué)習(xí)交流:

          - 即時(shí)通訊/推送技術(shù)開發(fā)交流4群:101279154[推薦]

          - 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM

          (本文同步發(fā)布于:http://www.52im.net/thread-2488-1-1.html

          二、參考文章

          三、更多資料

          Web端即時(shí)通訊新手入門貼:
          新手入門貼:詳解Web端即時(shí)通訊技術(shù)的原理

          Web端即時(shí)通訊技術(shù)盤點(diǎn)請(qǐng)參見:
          Web端即時(shí)通訊技術(shù)盤點(diǎn):短輪詢、Comet、Websocket、SSE

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

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

          更多WebSocket的詳細(xì)介紹請(qǐng)參見:
          新手快速入門:WebSocket簡明教程
          Socket.IO介紹:支持WebSocket、用于WEB端的即時(shí)通訊的框架
          socket.io和websocket 之間是什么關(guān)系?有什么區(qū)別?

          有關(guān)SSE的詳細(xì)介紹文章請(qǐng)參見:
          SSE技術(shù)詳解:一種全新的HTML5服務(wù)器推送事件技術(shù)

          更多WEB端即時(shí)通訊文章請(qǐng)見:
          http://www.52im.net/forum.php?mod=collection&action=view&ctid=15

          四、1問WebSocket:WebSocket協(xié)議只能瀏覽器發(fā)起么?

          不是。目前此協(xié)議的受眾的也不僅僅是web開發(fā)者。

          WebSocket只是一種協(xié)議,它和http協(xié)議一樣,使用類似okhttp的組件,可以在任何地方進(jìn)行調(diào)用,甚至可以借助WebSocket實(shí)現(xiàn)RPC框架。

          五、2問WebSocket:WebSocket和HTTP什么關(guān)系?

          WebSocket和http一樣,都是處于OSI模型中的最高層:應(yīng)用層。

          WebSocket借助http協(xié)議進(jìn)行握手,握手成功后,就會(huì)變身為TCP通道,從此與http不再相見。

          使用netstat或者ss,能夠看到對(duì)應(yīng)的連接,它與處于抽象層的socket,在外觀上沒有區(qū)別。

          更多WebSocket和HTTP的關(guān)系,以及與Socket的區(qū)別,可進(jìn)一步閱讀以下文章:

          WebSocket詳解(四):刨根問底HTTP與WebSocket的關(guān)系(上篇)

          WebSocket詳解(五):刨根問底HTTP與WebSocket的關(guān)系(下篇)

          WebSocket詳解(六):刨根問底WebSocket與Socket的關(guān)系

          六、3問WebSocket:WebSocket和長輪詢有什么區(qū)別?

          長輪詢,就是客戶端發(fā)送一個(gè)請(qǐng)求,服務(wù)端將一直在這個(gè)連接上等待(當(dāng)然有一個(gè)超長的超時(shí)時(shí)間),直到有數(shù)據(jù)才返回,它依然是一個(gè)一問一答的模式。比如著名的comted。

          WebSocket在握手成功后,就是全雙工的TCP通道,數(shù)據(jù)可以主動(dòng)從服務(wù)端發(fā)送到客戶端,處于鏈接兩端的應(yīng)用沒有任何區(qū)別。

          WebSocket創(chuàng)建的連接和Http的長連接是不一樣的。由于Http長連接底層依然是Http協(xié)議,所以它還是一問一答,只是Hold住了一條命長點(diǎn)的連接而已。

          長輪詢和Http長連接是阻塞的I/O,但WebSocket可以是非阻塞的(具體是多路復(fù)用)。

          這方面更深入的資料,請(qǐng)進(jìn)一步學(xué)習(xí):

          Comet技術(shù)詳解:基于HTTP長連接的Web端實(shí)時(shí)通信技術(shù)

          WEB端即時(shí)通訊:HTTP長連接、長輪詢(long polling)詳解

          七、4問WebSocket:如何創(chuàng)建一個(gè)WebSocket連接?

          WebSocket的連接創(chuàng)建是借助Http協(xié)議進(jìn)行的。這樣設(shè)計(jì)主要是考慮兼容性,在瀏覽器中就可以很方便的發(fā)起請(qǐng)求,看起來比較具有迷惑性。

          下圖是一個(gè)典型的由瀏覽器發(fā)起的ws請(qǐng)求,可以看到和http請(qǐng)求長的是非常相似的。

          但是,它只是請(qǐng)求階段長得像而已:

          請(qǐng)求的地址,一般是:ws://\*\*\*,或者是使用了SSL/TLS加密的安全協(xié)議wss:,用來標(biāo)識(shí)是WebSocket請(qǐng)求。

          1)首先,通過Http頭里面的Upgrade域,請(qǐng)求進(jìn)行協(xié)議轉(zhuǎn)換。如果服務(wù)端支持的話,就可以切換到WebSocket協(xié)議。簡單點(diǎn)講:連接已經(jīng)在那了,通過握手切換成ws協(xié)議,就是切換了連接的一個(gè)狀態(tài)而已。

          2)Connection域可以認(rèn)為是與Upgrade域配對(duì)的頭信息。像nginx等代理服務(wù)器,是要先處理Connection,然后再發(fā)起協(xié)議轉(zhuǎn)換的。

          3)Sec-WebSocket-Key 是隨機(jī)的字符串,服務(wù)器端會(huì)用這些數(shù)據(jù)來構(gòu)造出一個(gè) SHA-1 的信息摘要。如此操作,可以盡量避免普通 HTTP 請(qǐng)求被誤認(rèn)為 WebSocket 協(xié)議。

          其他的,像Sec-WebSocket*字樣的頭信息,表明了客戶端支持的子協(xié)議以及其他信息。像loT中很流行的mqtt,就可以作為WebSocket的子協(xié)議。

          使用javascript,可以很容易連接一個(gè)WebSocket服務(wù)端:

          <script>

            varws = newWebSocket('ws://localhost:80');

            ws.onopen = function() {

              console.log('ws onopen');

              ws.send('from client: hello');

            };

            ws.onmessage = function(e) {

              console.log('ws onmessage');

              console.log('from server: '+ e.data);

            };

            ...

          </script>

          更詳細(xì)的資料,請(qǐng)閱讀:《WebSocket詳解(三):深入WebSocket通信協(xié)議細(xì)節(jié)》。

          八、5問WebSocket:WebSocket如何處理數(shù)據(jù)?

          WebSocket是通過事件通知的方式運(yùn)行的。它包含四個(gè)事件和兩個(gè)動(dòng)作(發(fā)送和關(guān)閉)。

          WebSocket的事件:

          數(shù)據(jù)可直接通過Socket.send()方法進(jìn)行傳輸。

          通過chrome的Inspect->Network->WS,可以看到頁面上的WebSocket連接。

          如圖Opcode為2,表明它是一個(gè)二進(jìn)制幀:

          WebSocket有類似tcp協(xié)議的幀格式,在此不做過多解釋。(可以詳細(xì)閱讀:《理論聯(lián)系實(shí)際:從零理解WebSocket的通信原理、協(xié)議格式、安全性》)

          參考:https://tools.ietf.org/html/rfc6455#section-5.1

          九、6問WebSocket:如何使用Nginx做WebSocket的負(fù)載均衡?

          nginx官網(wǎng)已經(jīng)給出了例子。主要是Upgrade和Connection頭的設(shè)置。

          Nginx的中的配置如下:

          map $http_upgrade $connection_upgrade {

              default upgrade;

              ''close;

          }


          location /chat/{

              proxy_pass http://backend;

              proxy_http_version 1.1;

              proxy_set_header Upgrade $http_upgrade;

              proxy_set_header Connection $connection_upgrade;

          }

          需要注意的是,nginx做負(fù)載均衡,不需要配置ip_hash等參數(shù),nginx天然支持。由于ip_hash僅使用ip地址的前三個(gè)數(shù)字做hash,還有可能造成服務(wù)端的不均衡。

          特別注意:

          在IM聊天系統(tǒng)場景下,Nginx提供給WebSocket的這種所謂的“負(fù)載均衡”,只能解決傳統(tǒng)分布系統(tǒng)中的SLB服務(wù)器要做的事。

          通俗地說,Nginx只能幫助完成引導(dǎo)WebSocket客戶連接到哪一個(gè)WebSocket服務(wù)端實(shí)例,在IM集群情況下,如果兩個(gè)用戶處于不同的WebSocket實(shí)例下時(shí),它們之間的跨實(shí)例通信,Nginx是沒有辦法實(shí)現(xiàn)的,這一塊的邏輯還是得IM開發(fā)者自已來實(shí)現(xiàn)。

          總而言之,Nginx提供給WebSocket的所謂“負(fù)載均衡”,并不是IM開發(fā)者認(rèn)為的那種全功能集群!

          十、7問WebSocket:Java服務(wù)端怎么實(shí)現(xiàn)WebSocket?

          可以使用javax.WebSocket下的包,簡單的實(shí)現(xiàn)ws服務(wù)端。目前基本可以通過注解的方式去編寫代碼,比如ServerEndpoint。

          推薦使用基于netty的netty-socketio進(jìn)行服務(wù)端的編寫。由于使用的是netty,所以能夠在多個(gè)層面進(jìn)行切入,獲取一些統(tǒng)計(jì)數(shù)據(jù),執(zhí)行一些控制指令。socketio是一套解決方案,它有多個(gè)語言的客戶端,并處理了市面上大多數(shù)的兼容問題。

          友情忠告:socket.io幾乎是市面上最好的開源WebSocket解決方案,但netty-socketio這個(gè)開源工程并非socket.io官方團(tuán)隊(duì)維護(hù),而對(duì)于socket.io這個(gè)版本帝來說,其他的非官方版本能不能即時(shí)跟進(jìn),也是一個(gè)需要考慮的風(fēng)險(xiǎn)因素。

          十一、8問WebSocket:WebSocket能干些啥?

          1)通知功能:

          保持一個(gè)長連接,當(dāng)服務(wù)端游新的消息,能夠?qū)崟r(shí)的推送到使用方。像知乎的點(diǎn)贊通知、評(píng)論等,都可以使用WebSocket通信。

          某些使用H5的客戶端,為了簡化開發(fā),也會(huì)使用WebSocket進(jìn)行消息的通知,由于它是實(shí)時(shí)推送的,會(huì)有更好的用戶體驗(yàn)。

          2)數(shù)據(jù)收集:

          一些次優(yōu)級(jí)別的數(shù)據(jù),比如行為日志、trace、異常執(zhí)棧收集等,都可以開辟專門的WebSocket通道進(jìn)行傳輸。這能夠增加信息的集中度,并能及時(shí)的針對(duì)用戶的行為進(jìn)行合適的配置推送。由于大多數(shù)瀏覽器內(nèi)核都支持,它將使客戶端APM編程模型變得簡單。

          3)加密 && 認(rèn)證:

          雖然使用Fiddler、Charles等能夠抓到很多WebSocket包。但如果同時(shí)開啟SSL,傳輸加密后的二進(jìn)制數(shù)據(jù),會(huì)大幅增加破解的成本,會(huì)安全的多。

          4)反向控制鉤子:

          這個(gè)...由于是雙工長連接,服務(wù)端完全可以推送一些鉤子命令,甚至直接是代碼,在客戶端進(jìn)行執(zhí)行。比如截個(gè)屏,錄個(gè)音,種個(gè)小馬。用戶只要通過了授權(quán)申請(qǐng),剩下的就隨你發(fā)揮了。

          支付寶偷偷調(diào)用你的相機(jī)給你拍照的梗,我是相信的。

          十二:本文小結(jié)

          想當(dāng)年,cometd的出現(xiàn),驚為天人,振奮了很久。但技術(shù)日新月異,cometd已經(jīng)衰老,而Socket.io得到了快速發(fā)展。WebSocket經(jīng)過一段時(shí)間的混沌期,規(guī)范已經(jīng)越來越完善,使用也越來越方便,不需要再處理那么多的兼容。

          但它的本質(zhì),還是新瓶裝舊酒,換湯不換藥。WebSocket的發(fā)展得益于HTML5規(guī)范的制定。規(guī)范的意義,就是約束廠商們天馬行空的實(shí)現(xiàn),以及指明發(fā)展的方向。

          這當(dāng)然有典型的反例,那就是ie。現(xiàn)在,只有一群公認(rèn)的**,還堅(jiān)持在用。

          附錄:更多WEB端即時(shí)通訊資料

          新手入門貼:史上最全Web端即時(shí)通訊技術(shù)原理詳解
          Web端即時(shí)通訊技術(shù)盤點(diǎn):短輪詢、Comet、Websocket、SSE
          SSE技術(shù)詳解:一種全新的HTML5服務(wù)器推送事件技術(shù)
          Comet技術(shù)詳解:基于HTTP長連接的Web端實(shí)時(shí)通信技術(shù)
          新手快速入門:WebSocket簡明教程
          WebSocket詳解(一):初步認(rèn)識(shí)WebSocket技術(shù)
          WebSocket詳解(二):技術(shù)原理、代碼演示和應(yīng)用案例
          WebSocket詳解(三):深入WebSocket通信協(xié)議細(xì)節(jié)
          WebSocket詳解(四):刨根問底HTTP與WebSocket的關(guān)系(上篇)
          WebSocket詳解(五):刨根問底HTTP與WebSocket的關(guān)系(下篇)
          WebSocket詳解(六):刨根問底WebSocket與Socket的關(guān)系
          socket.io實(shí)現(xiàn)消息推送的一點(diǎn)實(shí)踐及思路
          LinkedIn的Web端即時(shí)通訊實(shí)踐:實(shí)現(xiàn)單機(jī)幾十萬條長連接
          Web端即時(shí)通訊技術(shù)的發(fā)展與WebSocket、Socket.io的技術(shù)實(shí)踐
          Web端即時(shí)通訊安全:跨站點(diǎn)WebSocket劫持漏洞詳解(含示例代碼)
          開源框架Pomelo實(shí)踐:搭建Web端高性能分布式IM聊天服務(wù)器
          使用WebSocket和SSE技術(shù)實(shí)現(xiàn)Web端消息推送
          詳解Web端通信方式的演進(jìn):從Ajax、JSONP 到 SSE、Websocket
          MobileIMSDK-Web的網(wǎng)絡(luò)層框架為何使用的是Socket.io而不是Netty?
          理論聯(lián)系實(shí)際:從零理解WebSocket的通信原理、協(xié)議格式、安全性
          微信小程序中如何使用WebSocket實(shí)現(xiàn)長連接(含完整源碼)
          八問WebSocket協(xié)議:為你快速解答WebSocket熱門疑問
          >> 更多同類文章 ……

          (本文同步發(fā)布于:http://www.52im.net/thread-2488-1-1.html



          作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
          出處:http://www.52im.net/space-uid-1.html
          交流:歡迎加入即時(shí)通訊開發(fā)交流群 215891622
          討論:http://www.52im.net/
          Jack Jiang同時(shí)是【原創(chuàng)Java Swing外觀工程BeautyEye】【輕量級(jí)移動(dòng)端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
          本博文 歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處(也可前往 我的52im.net 找到我)。


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 嘉禾县| 元朗区| 巴马| 万荣县| 修水县| 确山县| 六安市| 宕昌县| 神农架林区| 上饶市| 徐水县| 穆棱市| 桂平市| 运城市| 花垣县| 石城县| 哈密市| 新乐市| 乌审旗| 连城县| 行唐县| 营山县| 阳西县| 新兴县| 哈尔滨市| 江西省| 卓资县| 双桥区| 郁南县| 晋江市| 平安县| 荔浦县| 开鲁县| 万盛区| 西盟| 古丈县| 拉萨市| 九江市| 邵武市| 津市市| 宜良县|