Websocket協議之握手鍊接

Websocket協議是爲了解決web即時應用中服務器與客戶端瀏覽器全雙工通訊的問題而設計的,是徹底意義上的Web應用端的雙向通訊技術,能夠取代以前使用半雙工HTTP協議而模擬全雙工通訊,同時克服了帶寬和訪問速度等的諸多問題。協議定義爲ws和wss協議,分別爲普通請求和基於SSL的安全傳輸,佔用端口與http協議系統,ws爲80端口,wss爲443端口,這樣能夠支持HTTP代理。web

協議包含兩個部分,第一個是「握手」,第二個是數據傳輸。瀏覽器

1、Websocket URI

定義的兩個協議框架ws和wss與http相似,並且各自部分的要求也是在HTTP協議中使用的同樣,各自的URI以下:安全

ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
        wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]服務器

其中port是可選項,query前接「?」。websocket

2、握手(Opening & Closing Handshake)打開鏈接

當創建一個Websocket鏈接時,爲了保持基於HTTP協議的服務器軟件和中間件進行兼容工做,客戶端打開一個鏈接時使用與HTTP鏈接的同一個端口到服務器進行鏈接,這樣被設計爲一個升級的HTTP請求。網絡

一、發送握手請求

此時的鏈接狀態是CONNECTING,客戶端須要提供host、port、resource-name和一個是不是安全鏈接的標記,也就是一個WebSocket URI。框架

客戶端發送的一個到服務器端握手請求以下:socket

 

        GET /chat HTTP/1.1
        Host: server.example.com
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
        Origin: http://example.com
        Sec-WebSocket-Protocol: chat, superchat
        Sec-WebSocket-Version: 13


這個升級的HTTP請求頭中的字段順序是能夠隨便的。與普通HTTP請求相比多了一些字段。加密

  • Sec-WebSocket-Protocol:字段表示客戶端能夠接受的子協議類型,也就是在Websocket協議上的應用層協議類型。上面能夠看到客戶端支持chat和superchat兩個應用層協議,當服務器接受到這個字段後要從中選出一個協議返回給客戶端。
  • Upgrade:告訴服務器這個HTTP鏈接是升級的Websocket鏈接。
  • Connection:告知服務器當前請求鏈接是升級的。
  • Origin:該字段是用來防止客戶端瀏覽器使用腳本進行未受權的跨源攻擊,這個字段在WebSocket協議中很是重要。服務器要根據這個字段判斷是否接受客戶端的Socket鏈接。能夠返回一個HTTP錯誤狀態碼來拒絕鏈接。
  • Sec-WebSocket-Key:爲了表示服務器贊成和客戶端進行Socket鏈接,服務器端須要使用客戶端發送的這個Key進行校驗,而後返回一個校驗過的字符串給客戶端,客戶端驗證經過後才能正式創建Socket鏈接。服務器驗證方法是:首先進行 Key + 全局惟一標示符(GUID)「258EAFA5-E914-47DA-95CA-C5AB0DC85B11」鏈接起來,而後將鏈接起來的字符串使用SHA-1哈希加密,再進行base64加密,將獲得的字符串返回給客戶端做爲握手依據。其中GUID是一個對於不識別WebSocket的網絡端點不可能使用的字符串。
發送請求的要求:
  • 請求的WebSocket URI必需要是定義的有效的URI。
  • 若是客戶端已經有一個WebSocket鏈接到遠程服務器端,不管是否是同一個服務器,客戶端必需要等待上一個鏈接關閉後才能發送新的鏈接請求,也就是同一客戶端一次只能存在一個WebSocket鏈接。若是想同一個服務器有多個鏈接,客戶端必需要串行化進行。若是客戶端檢測到多個到不一樣服務器的鏈接,應該限制一個最大鏈接數,在web瀏覽器中應該設定最多能夠打開的標籤頁的數目。這樣能夠防止到遠程服務器的DDOS攻擊,但這是對到多個服務器的鏈接,若是是到同一個服務器鏈接,並無數目限制。
  • 若是使用了代理服務器,那麼客戶端創建鏈接的時候須要告知代理服務器向目標服務器打開TCP鏈接。
  • 若是鏈接沒有打開,必定是某一方出現錯誤,此時客戶端必需要關閉再次鏈接的嘗試。
  • 鏈接創建後,握手必需要是一個有效的HTTP請求
  • 請求的方式必須是GET,HTTP協議的版本至少是1.1
  • Upgrade字段必須包含並且必須是"websocket",Connection字段必須內容必須是「Upgrade」
  • Sec-Websocket-Version必須,並且必須是13

二、返回握手應答

服務器返回正確的相應頭後,客戶端驗證後將創建鏈接,此時狀態爲OPEN。服務器響應頭以下:
        HTTP/1.1 101 Switching Protocols
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
        Sec-WebSocket-Protocol: chat
響應頭握手過程當中是服務器返回的是否贊成握手的依據。
  • 首行返回的是HTTP/1.1協議版本和狀態碼101,表示變換協議(Switching Protocol)
  • Upgrade 和 Connection:這兩個字段是服務器返回的告知客戶端贊成使用升級並使用websocket協議,用來完善HTTP升級響應
  • Sec-WebSocket-Accept:服務器端將加密處理後的握手Key經過這個字段返回給客戶端表示服務器贊成握手創建鏈接。
  • Sec-Websocket-Procotol:服務器選擇的一個應用層協議。
上述響應頭字段被客戶端瀏覽器解析,若是驗證到Sec-WebSocket-Accept字段的信息符合要求就會創建鏈接,同時就能夠發送WebSocket的數據幀了。若是該字段不符合要求或者爲空或者HTTP狀態碼不爲101,就不會創建鏈接。
服務器端響應步驟:
  • 解析握手請求頭:獲取握手依據Key並進行處理,檢測HTTP的GET請求和版本是否準確,Host字段是否有權限,Upgrade字段中websocket是一個與大小寫無關的ASCII字符串,Connection字段是一個大小寫無關的"Upgrade"ASCII字符串,Websocket協議版本必須爲13,其餘的關於Origin、Protocol和Extensions可選。
  • 發送握手響應頭:檢測是不是wss協議鏈接,若是是就是用TLS握手鍊接,不然就是普通鏈接。服務器能夠添加額外的驗證信息到客戶端進行驗證。當進行一系列驗證以後,服務器必須返回一個有效的HTTP響應頭。響應頭中每一行一個字段,結束必須爲「\r\n」,使用的ABNF語法。
除了上述必要頭字段以外,其餘的HTTP協議定義的字段均可以使用,如Set-Cookie等。
相關文章
相關標籤/搜索