关于websocket
這個是一次組內(nèi)分享,關(guān)于websocket的協(xié)議和應(yīng)用的。文章在分享之前就寫好了,整理下放出來。
對應(yīng)的PPT地址是:http://websocket.funaio.com
從推送技術(shù)開始說
一篇文章10 Years of Push Technology, Comet, and WebSockets(http://cometdaily.com/2011/07/06/push-technology-comet-and-websockets-10-years-of-history-from-lightstreamers-perspective/)非常詳細的說明清楚了從1996-2007年推送技術(shù)的更新。2000年之前為第一波Push技術(shù),使用的概念叫Webcasting。大致思想就是用戶來服務(wù)端注冊一個或者多個通道channel,然后服務(wù)端確定給某些個channel或某個channel發(fā)送消息。2000到2007年最火的詞叫comet,比如有Polling(這個是最普通的輪詢),Long Polling(hold住HTTP的response端,當有消息的時候才返回),至于HTTP發(fā)起是在不同的哪些地方,Ajax,Flash,Iframe,然后就有各自不同的叫法和名詞。但是不管什么技術(shù),都限制于瀏覽器,因為瀏覽器只能發(fā)起HTTP請求。但是推送最好的一種方法當然是保持Socket長連接,瀏覽器如何能發(fā)起TCP連接呢?HTML5的Websocket技術(shù)就解決了這個問題。
websocket概述
現(xiàn)狀
websocket的版本發(fā)展:
draft-hixie-00
draft-hixie-76
draft-hybi-00
draft-hybi-17
RFC 6455
所以有的地方會出現(xiàn)hixie,hybi的字樣,純粹是為了滿足之前的版本。好消息是從2011年12月份開始,websocket的RFC正式版出來了。
客戶端現(xiàn)狀
從客戶端來講,大部分瀏覽器支持的是hybi-13版本,比如我使用的chrome v24,firefox v16。相信各家瀏覽器都很快能出現(xiàn)支持RFC版本的瀏覽器了。網(wǎng)上有很多文章說“支持websocket的瀏覽器”,這個說法其實是不對的,至少是不完整的。比如Chrome從草案開始就已經(jīng)支持websocket了,你拿一個支持hixie76版本的chrome調(diào)用實現(xiàn)了RFC 6455的服務(wù)端,那是怎么樣也對不上的。所以說“支持websocket的瀏覽器”還應(yīng)該多帶一句,支持什么版本。
瀏覽器來說還分為手機瀏覽器和PC瀏覽器。手機瀏覽器特別是android上的瀏覽器版本支持websocket的比PC上少很多(這可能和大家?guī)缀醪粫ザㄆ诟率謾C瀏覽器有關(guān))。網(wǎng)上對那些版本瀏覽器支持那些版本的websocket有好多文章進行統(tǒng)計了。但是由于瀏覽器種類繁多,版本之多,記住這些版本,不如在定義需求的時候明確我需要支持哪些瀏覽器的哪些版本,然后寫一個簡單例子試一下更為準確。
服務(wù)端現(xiàn)狀
下面是服務(wù)端。服務(wù)端對websocket的語言開發(fā)已經(jīng)是沒有問題了。http://en.wikipedia.org/wiki/WebSocket wiki上列出了各種服務(wù)端語言開發(fā)websocket的第三方包了。可以直接拿來用,也可以根據(jù)協(xié)議自己開發(fā)個websocket包,比如http://www.cnblogs.com/yjf512/archive/2013/02/18/2915171.html。甚至于像apache,nginx(1.3.13)這些現(xiàn)成的web服務(wù)器產(chǎn)品也都漸漸支持websocket了(nginx現(xiàn)在只是支持nginx代理)。
socket.io這個包是node上用的最多的一個第三方包。它其實并不僅僅是websocket。官方的faq http://socket.io/#faq 也說明清楚了為什么它不直接叫“websocket”包。socket.io的js包可以給客戶端使用,也可以給服務(wù)端使用,客戶端使用socket.io能很簡單建立websocket連接,但是上,支持websocket的瀏覽器是不需要使用socket.io來建立websocket連接的。在服務(wù)端,使用socket.io并不是只能創(chuàng)建websocket服務(wù)器,就是說socket.io要建立的服務(wù)是“socket服務(wù)”而不僅僅是“websocket服務(wù)”。
websocket的原理
websocket是一種協(xié)議,本質(zhì)上和http,tcp一樣。協(xié)議是用來說明數(shù)據(jù)是如何傳輸?shù)摹K膗rl前綴是ws:// 或者wss://,后者是加密的websocket。它的url諸如這樣:ws://10.16.15.64:3201/
客戶端和服務(wù)端進行websocket交互的方式也有人理解為“HTTP握手+TCP數(shù)據(jù)傳輸”的方式。
HTTP握手+TCP數(shù)據(jù)傳輸
握手和傳輸?shù)恼麄€流程是這樣的:
瀏覽器(支持Websocket的瀏覽器)像HTTP一樣,發(fā)起一個請求,然后等待服務(wù)端的響應(yīng)
服務(wù)器返回握手響應(yīng),告訴瀏覽器請將后續(xù)的數(shù)據(jù)按照websocket制定的數(shù)據(jù)格式傳過來
瀏覽器和服務(wù)器的socket連接不中斷,此時這個連接和http不同的是它是雙工的了
瀏覽器和服務(wù)器有任何需要傳遞的數(shù)據(jù)的時候使用這個長連接進行數(shù)據(jù)傳遞
這里說它是HTTP握手,是因為瀏覽器和服務(wù)器在建立長連接的握手過程是按照HTTP1.1的協(xié)議發(fā)送的,有Request,Request Header, Response, Response Header。但是不同的是Header里面的字段是有特定含義的。
說它是TCP傳輸,主要體現(xiàn)在建立長連接后,瀏覽器是可以給服務(wù)器發(fā)送數(shù)據(jù),服務(wù)器也可以給瀏覽器發(fā)送請求的。當然它的數(shù)據(jù)格式并不是自己定義的,是在要傳輸?shù)臄?shù)據(jù)外層有ws協(xié)議規(guī)定的外層包的。
握手過程
這是一個握手過程的例子。
Upgrade頭表示的意思是“客戶端除了http之外也支持websocket協(xié)議,而且更傾向使用websocket,服務(wù)端如果支持的話,咱們就換websocket協(xié)議吧”
sec-websocket-version:是指出瀏覽器支持的websocket號。這里是支持hybi-13。這里是不會出現(xiàn)9-12的版本號的。websocket協(xié)議規(guī)定9-12是保留字段。
sec-websocket-key:算是一種驗證返回回來的服務(wù)端是否是支持websocket的驗證算法。與Response中的sec-websocket-accept是對應(yīng)的。
sec-websocket-accept與sec-websocket-key的對應(yīng)算法是:
sec-websocket-accept = base64(hsa1(sec-websocket-key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11))
如果返回的sec-websocket-accept不對,在chrome下會出現(xiàn)Sec-WebSocket-Accept dismatch的錯誤。
Response返回的HTTP Staus是101,代表服務(wù)端說“我們雙方后面就按照websocket協(xié)議來進行數(shù)據(jù)傳輸吧”
數(shù)據(jù)傳輸過程
websocket的數(shù)據(jù)傳輸是frame形式傳輸?shù)?#xff0c;比如會將一條消息分為幾個frame,按照先后順序傳輸出去。這樣做會有幾個好處:
1 大數(shù)據(jù)的傳輸可以分片傳輸,不用考慮到數(shù)據(jù)大小導致的長度標志位不足夠的情況。
2 和http的chunk一樣,可以邊生成數(shù)據(jù)邊傳遞消息,即提高傳輸效率。
傳輸協(xié)議:
FIN:1位,用來表明這是一個消息的最后的消息片斷,當然第一個消息片斷也可能是最后的一個消息片斷
RSV1, RSV2, RSV3: 分別都是1位,如果雙方之間沒有約定自定義協(xié)議,那么這幾位的值都必須為0,否則必須斷掉WebSocket連接
Opcode:4位操作碼,定義有效負載數(shù)據(jù),如果收到了一個未知的操作碼,連接也必須斷掉,以下是定義的操作碼:
????? *? %x0 表示連續(xù)消息片斷
????? *? %x1 表示文本消息片斷
????? *? %x2 表未二進制消息片斷
????? *? %x3-7 為將來的非控制消息片斷保留的操作碼
????? *? %x8 表示連接關(guān)閉
????? *? %x9 表示心跳檢查的ping
????? *? %xA 表示心跳檢查的pong
????? *? %xB-F 為將來的控制消息片斷的保留操作碼
Mask:1位,定義傳輸?shù)臄?shù)據(jù)是否有加掩碼,如果設(shè)置為1,掩碼鍵必須放在masking-key區(qū)域,客戶端發(fā)送給服務(wù)端的所有消息,此位的值都是1
Payload length: 傳輸數(shù)據(jù)的長度,以字節(jié)的形式表示:7位、7+16位、或者7+64位。如果這個值以字節(jié)表示是0-125這個范圍,那這個值就表示傳輸數(shù)據(jù)的長度;如果這個值是126,則隨后的兩個字節(jié)表示的是一個16進制無符號數(shù),用來表示傳輸數(shù)據(jù)的長度;如果這個值是127,則隨后的是8個字節(jié)表示的一個64位無符合數(shù),這個數(shù)用來表示傳輸數(shù)據(jù)的長度。多字節(jié)長度的數(shù)量是以網(wǎng)絡(luò)字節(jié)的順序表示。負載數(shù)據(jù)的長度為擴展數(shù)據(jù)及應(yīng)用數(shù)據(jù)之和,擴展數(shù)據(jù)的長度可能為0,因而此時負載數(shù)據(jù)的長度就為應(yīng)用數(shù)據(jù)的長度
Masking-key:0或4個字節(jié),客戶端發(fā)送給服務(wù)端的數(shù)據(jù),都是通過內(nèi)嵌的一個32位值作為掩碼的;掩碼鍵只有在掩碼位設(shè)置為1的時候存在
Payload data: (x+y)位,負載數(shù)據(jù)為擴展數(shù)據(jù)及應(yīng)用數(shù)據(jù)長度之和
Extension data:x位,如果客戶端與服務(wù)端之間沒有特殊約定,那么擴展數(shù)據(jù)的長度始終為0,任何的擴展都必須指定擴展數(shù)據(jù)的長度,或者長度的計算方式,以及在握手時如何確定正確的握手方式。如果存在擴展數(shù)據(jù),則擴展數(shù)據(jù)就會包括在負載數(shù)據(jù)的長度之內(nèi)
Application data:y位,任意的應(yīng)用數(shù)據(jù),放在擴展數(shù)據(jù)之后,應(yīng)用數(shù)據(jù)的長度=負載數(shù)據(jù)的長度-擴展數(shù)據(jù)的長度
讀取數(shù)據(jù)需要按照這個格式讀取,發(fā)送數(shù)據(jù)也需要按照這個格式發(fā)送返回。
代碼示例:
http://www.cnblogs.com/yjf512/archive/2013/02/18/2915171.html
應(yīng)用:
1 chatofPemelo
聊天室
https://github.com/NetEase/chatofpomelo
2 osxair
遠程控制air
https://github.com/jianfengye/MyWorks/tree/master/osxair
3 nginx1.3.13
nginx1.3.13只是支持了websocket代理
Feature: support for proxying of WebSocket connections.
參考文章
http://m.udpwork.com/item/6758.html
http://www.websocket.org/aboutwebsocket.html
http://tools.ietf.org/html/rfc6455
http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-13
http://www.cnblogs.com/yjf512/archive/2013/02/18/2915171.html
總結(jié)
以上是生活随笔為你收集整理的关于websocket的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ssp是什么(大厂ssp是什么意思)
- 下一篇: ips是什么意思(IPS屏是什么意思)