Websocket解析及實現

Websocket是什麼?

Websocket是一個由於應用場景愈來愈複雜而提出的,針對瀏覽器和web服務器之間雙向持續通訊而設計,並且優雅地兼容HTTP的協議(我猜測:同時由於創建在HTTP上,也能夠利用好HTTP原有的基礎好比basic認證)。php

網絡模型結構上來講呢,html

WebSocket 實際上指的是一種協議,與咱們熟知的Http協議是同等的一個網絡協議。用網絡模型結構來解釋的話,WebSocket和Http協議都屬於應用層協議,二者都基於傳輸層的TCP協議。
websocket協議本質上是一個基於tcp的協議,是先經過HTTP/HTTPS協議發起一條特殊的http請求進行握手後建立一個用於交換數據的TCP鏈接,此後服務端與客戶端經過此TCP鏈接進行實時通訊。html5


與http協議的關係:jquery

WebSocket不是Http協議,Http協議只是被WebSocket使用來創建鏈接,鏈接創建了之後客戶端與服務器的雙向通訊就與Http無關了。
借用了http的協議完成握手的一個新協議,能夠說是基於http協議,能夠說是http協議的一種補充,也能夠說與http協議毫無關係nginx

Websocket的做用和優勢?

非WebSocket的實時信息傳遞技術?

WebSocket 是什麼原理?爲何能夠實現持久鏈接? - 知乎git

  • 輪詢

輪詢是由客戶端定時向服務端發起查詢數據的請求的一種實現方式。早期的輪詢是經過不斷自動刷新頁面而實現的。
在特定的時間間隔(例如1秒),由瀏覽器向服務器發出一個Http Request,而後服務器返回最新的數據給客戶端瀏覽器,從而給出一種服務端實時推送的假象。因爲Http Request的Header(請求頭)很長,而傳輸的數據可能很短就只佔一點點,每次請求消耗的帶寬和服務器資源大部分都消耗在Header上。(想一想ajax技術和全頁面傳值的資源消耗)github

  • ajax輪詢

ajax輪詢,又被稱爲Comet,由客戶端不停地請求服務器端,查詢有沒有新消息,而後再由服務器返回結果;是輪詢的一種優化,實現了無刷新更新數據,而且不用傳遞header頭的信息,傳遞內容更少。web

但本質上這些方式均是客戶端定時輪詢服務端,這種方式的最顯著的缺點是若是客戶端數量龐大而且定時輪詢間隔較短服務端將承受響應這些客戶端海量請求的巨大的壓力。ajax

  • 長輪詢

長輪詢(long polling)是另外一種流行的通訊方法,客戶端向服務器請求信息,並在設定的時間段內打開一個鏈接。服務器若是沒有任何信息,會保持請求打開,直到有客戶端可用的信息,或者直到指定的超時時間用完爲止。這時,客戶端從新向服務器請求信息。長輪詢也稱做Comet(前面已經提到過)或者反向AJAX。Comet延長HTTP響應的完成,直到服務器有須要發送給客戶端的內容,這種技術經常稱做「掛起GET」或「擱置POST」。重要的是要知道,當信息量很大時,長輪詢相對於傳統輪詢並無明顯的性能優點,由於客戶端必須頻繁地重連到服務器以讀取新信息,形成網絡的表現和快速輪詢相同。長輪詢的另外一個問題是缺少標準實現。算法

長輪詢其實原理跟ajax輪詢差很少,都是採用輪詢的方式,不過採起的是阻塞模型(一直打電話,沒收到就不掛電話),也就是說,經過一次請求,詢問服務器有沒有新消息更新,若是沒有新消息時,會保持長鏈接,就一直不返回Response給客戶端。直到有消息才返回,返回完以後,客戶端再次創建鏈接,周而復始。

在數據更新不夠頻繁的狀況下,使用輪詢方法獲取數據時客戶端常常會獲得沒有數據的響應,顯然這樣的輪詢是一個浪費網絡資源的無效的輪詢。長輪詢則是針對普通輪詢的這種缺陷的一種改進方案,其具體實現方式是若是當前請求沒有數據能夠返回,則繼續保持當前請求的網絡鏈接狀態,直到服務端有數據能夠返回或者鏈接超時。長輪詢經過這種方式減小了客戶端與服務端交互的次數,避免了一些無謂的網絡鏈接。可是若是數據變動較爲頻繁,則長輪詢方式與普通輪詢在性能上並沒有顯著差別。同時,增長鏈接的等待時間,每每意味着併發性能的降低。

長輪詢雖然下降了服務器的負載,可是須要服務器有很高的併發能力才能夠。
而目前處理高併發的模型基本都是異步非阻塞的模型(好比nginx)。
既想阻塞,又想高併發,幾乎不可能。

所謂流是指客戶端在頁面之下向服務端發起一個長鏈接請求,服務端收到這個請求後響應它並不斷更新鏈接狀態,以確保這個鏈接在客戶端與服務端之間一直有效。服務端能夠經過這個鏈接將數據主動推送到客戶端。顯然,這種方案實現起來相對比較麻煩,並且可能被防火牆阻斷。

在流化技術中,客戶端發送一個請求,服務器發送並維護一個持續更新和保持打開(能夠是無限或者規定的時間段)的開放響應。每當服務器有須要交付給客戶端的信息時,它就更新響應。看起來,流化是可以適應不可預測的信息交付的極佳方案,可是服務器從不發出完成HTTP響應的請求,從而使鏈接一直保持打開。在這種狀況下,代理和防火牆可能緩存響應,致使信息交付的延遲增長。所以,許多流化的嘗試對於存在防火牆和代理的網絡是不友好的。

流技術方案一般就是在客戶端的頁面使用一個隱藏的窗口向服務端發出一個長鏈接的請求。服務器端接到這個請求後做出迴應並不斷更新鏈接狀態以保證客戶端和服務器端的鏈接不過時。經過這種機制能夠將服務器端的信息源源不斷地推向客戶端。這種機制在用戶體驗上有一點問題,須要針對不一樣的瀏覽器設計不一樣的方案來改進用戶體驗,同時這種機制在併發比較大的狀況下,對服務器端的資源是一個極大的考驗。

傳統方法的缺點?

Web 通訊 之 長鏈接、長輪詢(long polling) - hoojo - 博客園

上述方法提供了近乎實時的通訊,
可是它們也涉及HTTP請求和響應首標,
包含了許多附加和沒必要要的首標數據與延遲。

此外,在每一種狀況下,客戶端都必須等待請求返回,才能發出後續的請求,而這顯著地增長了延遲。

以上四種方法的後三種呢,都實現了真正的雙工通訊,但都是單向連接,須要被動的請求服務器,而不是由服務器自動發給客戶端。(仍是在代碼層面上下功夫,可是這種狀況下,明顯須要從協議層去想辦法)

首先就是很是消耗資源,不斷地創建HTTP鏈接,而後等待服務端處理,能夠體現HTTP協議的另一個特色,被動性。其次呢,
ajax輪詢須要服務器有很快的處理速度和資源,
長輪詢須要有很高的併發,也就是同時處理請求的能力

Websocket的優勢?

基於此,websocket出現了,它解決了http不利於這種場景下(聊天,視頻...)的兩個問題:
http協議是一個無狀態的,被動的協議(不持久,服務端沒法主動發送信息給客戶端)

Websocket只須要一次HTTP握手,因此說整個通信過程是創建在一次鏈接/狀態中,也就避免了HTTP的非狀態性,服務端會一直知道你的信息,直到你關閉請求,這樣就解決了接線員要反覆解析HTTP協議,還要查看identity info的信息。

同時由客戶主動詢問,轉換爲服務器(推送)有信息的時候就發送(固然客戶端仍是等主動發送信息過來的。。),沒有信息的時候就交給接線員(Nginx),不須要佔用自己速度就慢的客服(Handler)了

因此,,,
Websocket能更好的實現雙向通訊且節省服務器資源和帶寬。

websocket協議解析?

wensocket協議包含兩部分:一部分是「握手」,一部分是「數據傳輸」。爲了便於演示,咱們採用swoole創建一個websocket服務器來演示。

握手部分:

Websocket協議之握手鍊接 - Oshyn —— 樂而學,學而樂 - CSDN博客

①客戶端向服務端發起鏈接請求
圖片描述
如圖,咱們在請求服務器的時候,發送了這樣的request header。
下面咱們就一些比較重要的字段信息進行說明:

* Connection:Upgrade #通知服務器協議升級 Upgrade:websocket  #協議升級爲websocket協議
* Host:0.0.0.0:9501  #升級協議的服務主機:端口地址
* Sec-WebSocket-Key:K8o1cNIxO2pR6inTIDBSgg== #傳輸給服務器的key
* Sec-WebSocket-Version:13 #websocket協議版本13

Sec-WebSocket-Key有什麼用呢?客戶端將這個key發送給服務器,服務器將這個key進行處理,將處理後的key返回給客戶端,客戶端根據這個key是否正確來判斷是否創建鏈接。
②:服務端返回握手應答
圖片描述
如圖,咱們看到websocket協議狀態碼是101.

101表示協議切換成功。

咱們查看websocket的response header。如圖:
圖片描述
下面解釋下reponse header字段的含義

* Connection:Upgrade #協議升級成功
* Sec-WebSocket-Accept:GnoYH/ip/ZMh+a5rX5P/YR6e68g= #服務端處理以後的key
* Sec-WebSocket-Version:13#websocket 協議版本號
* Upgrade:websocket#協議升級爲websocket

至此,websocket握手成功!下面就盡情的傳輸數據吧!

數據傳輸部分:

數據傳輸須要客戶端,非websocket客戶端不能與websocket服務器通訊,那麼怎麼實現websocket客戶端呢?

* Chrome/Firefox/高版本IE/Safari等瀏覽器內置了JS語言的WebSocket客戶端

* 可使用一些擴展來實現websocket客戶端。如php的swoole、workerman。

怎麼使用websocket實現聊天室?

能夠參考的DEMO

PHP源碼及DEMO:
洞悉/websocket - 碼雲

swoole 服務端120行代碼構建一個websocket 聊天室. - 我的文章 - SegmentFault

基於swoole和websocket的直播攝像頭的demo

NodeJS實現Websocket聊天室:
利用express+socket.io實現一個簡易版聊天室 - zp的筆記 - SegmentFault

JAVA實現websocket聊天室:
websocket筆記以及一個微型聊天室例子 - niiiu的web雜談 - SegmentFault

可能出現的問題?

Chrome下會報這個

WebSocket connection to 'ws://127.0.0.1:8000/' failed: Error in
connection establishment: net::ERR_CONNECTION_REFUSED

Firefox下會報這個

Firefox 沒法創建到 ws://... 服務器的鏈接;

那麼如何解決呢?
目前來看,主要是三個方面的問題,

* URL路徑,這個要注意一下文件名或者路徑是否是有問題; 
* 其次,看下瀏覽器的支持問題,是否有須要開啓的配置;
* 最後,看看是否是websocket的進程是否是不在運行中,不然瀏覽器會鏈接不上;

第二種問題很容易解決了,about:config裏搜websocket,檢查是否有錯誤的配置項。

這裏着重說下最後一種問題,

運行程序以前,要先在服務器跑一下他的php文件
在命令行cd到文件夾下php websocket.php,報的這個錯

PHP Fatal error:  Uncaught Error: Call to undefined function socket_create() in E:\phpStudy\WWW\Month10\websocket\websocket.php:87
Stack trace:
#0 E:\phpStudy\WWW\Month10\websocket\websocket.php(19): Sock->WebSocket('127.0.0.1', 8000)
#1 E:\phpStudy\WWW\Month10\websocket\websocket.php(5): Sock->__construct('127.0.0.1', 8000)
#2 {main}
  thrown in E:\phpStudy\WWW\Month10\websocket\websocket.php on line 87

Fatal error: Uncaught Error: Call to undefined function socket_create() in E:\phpStudy\WWW\Month10\websocket\websocket.php:87
Stack trace:
#0 E:\phpStudy\WWW\Month10\websocket\websocket.php(19): Sock->WebSocket('127.0.0.1', 8000)
#1 E:\phpStudy\WWW\Month10\websocket\websocket.php(5): Sock->__construct('127.0.0.1', 8000)
#2 {main}
  thrown in E:\phpStudy\WWW\Month10\websocket\websocket.php on line 87

注意要開啓websocket的php拓展,解決方法以下:

遭遇了"Call to undefined function socket_create()" - 可視化空間 - ITeye博客

  1. 找到php.ini,看 extension=php_gd2.dll 和 extension=php_sockets.dll 擴展是否打開;
  2. 看phpInfo()顯示的內容裏,socket模塊是否爲enable;

我檢查了一下,發現都是符合的。但錯誤仍然出現?怎麼回事呢?

後來我才發現,原來是我在phpInfo()裏看到的和在cmd窗口裏使用的php不是同一個東西。

緣由是我屢次安裝過php. 先前的php在系統的環境變量裏面註冊了path。因此在cmd窗口裏使用的是之前的php.
而在phpInfo()裏顯示的是如今的php的設置。

解決的辦法很簡單了,就把系統環境變量裏的path裏,指向老的Php的路徑改成指向正在使用的Php的路徑。這樣在cmd裏的php和在瀏覽器裏的php就是同一個東西了。

Websocket的應用場景?

決定手頭的工做是否須要使用WebSocket技術的方法很簡單:

* 你的應用提供多個用戶相互交流嗎?
* 你的應用是展現服務器端常常變更的數據嗎?

若是你的回答是確定的,那麼請考慮使用WebSocket。若是你仍然不肯定,並想要更多的靈感,這有一些殺手鐗的案例。

1.社交訂閱
對社交類的應用的一個裨益之處就是可以即時的知道你的朋友正在作什麼。雖然聽起來有點可怕,可是咱們都喜歡這樣作。你不會想要在數分鐘以後才能知道一個家庭成員在餡餅製做大賽獲勝或者一個朋友訂婚的消息。你是在線的,因此你的訂閱的更新應該是實時的。
2.多玩家遊戲
網絡正在迅速轉變爲遊戲平臺。在不使用插件(我指的是Flash)的狀況下,網絡開發者如今能夠在瀏覽器中實現和體驗高性能的遊戲。不管你是在處理DOM元素、CSS動畫,HTML5的canvas或者嘗試使用WebGL,玩家之間的互動效率是相當重要的。我不想在我扣動扳機以後,個人對手卻已經移動位置。

3.協同編輯/編程
咱們生活在分佈式開發團隊的時代。平時使用一個文檔的副本就知足工做需求了,可是你最終須要有一個方式來合併全部的編輯副本。版本控制系統,好比Git可以幫助處理某些文件,可是當git發現一個它不能解決的衝突時,你仍然須要去跟蹤人們的修改歷史。經過一個協同解決方案,好比WebSocket,咱們可以工做在同一個文檔,從而省去全部的合併版本。這樣會很容易看出誰在編輯什麼或者你在和誰同時在修改文檔的同一部分。
4.點擊流數據
分析用戶與你網站的互動是提高你的網站的關鍵。HTTP的開銷讓咱們只能優先考慮和收集最重要的數據部分。而後,通過六個月的線下分析,咱們意識到咱們應該收集一個不一樣的判斷標準——一個看起來不是那麼重要可是如今卻影響了一個關鍵的決定。與HTTP請求的開銷方式相比,使用Websocket,你能夠由客戶端發送不受限制的數據。想要在除頁面加載以外跟蹤鼠標的移動?只須要經過WebSocket鏈接發送這些數據到服務器,並存儲在你喜歡的NoSQL數據庫中就能夠了(MongoDB是適合記錄這樣的事件的)。如今你能夠經過回放用戶在頁面的動做來清楚的知道發生了什麼。

5.股票基金報價
金融界瞬息萬變——幾乎是每毫秒都在變化。咱們人類的大腦不能持續以那樣的速度處理那麼多的數據,因此咱們寫了一些算法來幫咱們處理這些事情。雖然你不必定是在處理高頻的交易,可是,過期的信息也只能致使損失。當你有一個顯示盤來跟蹤你感興趣的公司時,你確定想要隨時知道他們的價值,而不是10秒前的數據。使用WebSocket能夠流式更新這些數據變化而不須要等待。
6.體育實況更新
如今咱們開始討論一個讓人們激情澎湃的愚蠢的東西——體育。我不是運動愛好者,可是我知道運動迷們想要什麼。當愛國者在打比賽的時候,個人妹夫將會沉浸於這場比賽中而不能自拔。那是一種瘋狂癡迷的狀態,徹底發自心裏的。我雖然不理解這個,可是我敬佩他們與運動之間的這種強烈的聯繫,因此,最後我能作的就是給他的體驗中下降延遲。若是你在你的網站應用中包含了體育新聞,WebSocket可以助力你的用戶得到實時的更新。

7.多媒體聊天視頻會議並不能代替和真人相見,但當你不能在同一個屋子裏見到你談話的對象時,視頻會議是個不錯的選擇。儘管視頻會議私有化作的「不錯」,但其使用仍是很繁瑣。我但是開放式網絡的粉絲,因此用WebSockets getUserMedia API和html5音視頻元素明顯是個不錯的選擇。WebRTC的出現瓜熟蒂落的成爲我剛纔歸納的組合體,它看起來頗有但願,但其缺少目前瀏覽器的支持,因此就取消了它成爲候選人的資格。

8.基於位置的應用
愈來愈多的開發者借用移動設備的GPS功能來實現他們基於位置的網絡應用。若是你一直記錄用戶的位置(好比運行應用來記錄運動軌跡),你能夠收集到更加細緻化的數據。若是你想實時的更新網絡數據儀表盤(能夠說是一個監視運動員的教練),HTTP協議顯得有些笨拙。借用WebSocket TCP連接可讓數據飛起來。
9.在線教育上學花費愈來愈貴了,但互聯網變得更快和更便宜。在線教育是學習的不錯方式,尤爲是你能夠和老師以及其餘同窗一塊兒交流。很天然,WebSockets是個不錯的選擇,能夠多媒體聊天、文字聊天以及其它優點如與別人合做一塊兒在公共數字黑板上畫畫...

其餘

Websocket攻擊

【技術分享】WebSocket漏洞與防禦詳解_黑客技術

一個socket是一次網絡通訊中的一個端點。socket老是分爲兩部分:一個IP地址和一個端口。

例如:當您訪問www.securelayer7.net時,你的計算機和網站的服務器正在使用socket(端點)進行通訊。網站的端點將是:www.securelayer7.net:80,你的計算機的端點將是你的IP地址,後跟任何隨機端口號,如192.168.0.111:6574

跨站websocket劫持
網絡敏感信息泄露
DDOS攻擊(默認狀況下,WebSockets容許無限制的鏈接致使DOS)

參考文檔

WebSocket初探

WebSocket實現原理

WebSocket 是什麼原理?如何實現消息實時推送?

WebSocket原理

相關文章
相關標籤/搜索