Websocket 基礎篇

轉自:https://www.qcloud.com/community/article/142731?fromSource=gwzcw.116656.116656.116656


一、理解 socket , tcp , websocket, http 的聯繫和區別

socket

socket 是應用層與 TCP/IP 協議族通信的中間軟件抽象層,它是一組接口

一個套接字接口構成一個連接的一端,而一個連接可完全由一對套接字接口規定

socket 起源於 Unix,而 Unix/Linux 基本哲學之一就是“一切皆文件”,都可以用“打開 open –> 讀寫 write/read –> 關閉 close”模式來操作。socket 即是一種特殊的文件,一些 socket 函數就是對其進行的操作(讀/寫 IO、打開、關閉)

Unix 中的 Socket,讀起來太抽象,打個具體的比方吧,我們的消息隊列文件就是 s 類型的文件,就是 socket 文件:(appplatform 框架下消息隊列文件存在/tmp/app 目錄下)

ps:appplatfrom 裏面配的兩個 MsgQKey 在 ServiceConfig.xml 文件中配置的,成對出現可以在這裏查到。27e5→27e50(加個 0)→163408(再換成十進制)。。。扯遠了。

網絡中的 socekt:

在本地可以通過進程 PID 來唯一標識一個進程,但是在網絡中這是行不通的。其實 TCP/IP 協議族已經幫我們解決了這個問題,網絡層的“ip 地址”可以唯一標識網絡中的主機,而傳輸層的“協議+端口”可以唯一標識主機中的應用程序(進程)。這樣利用三元組(ip 地址,協議,端口)就可以標識網絡的進程了,網絡中的進程通信就可以利用這個標誌與其它進程進行交互。

websocket

先看網絡協議圖:

就是說 Websocket 是應用層協議的一種,建立在 http 協議之上,它的誕生是爲了創建一種「雙向通信」的協議,來作爲 HTTP 協議的一個替代者。

情不自禁要問,爲什麼要用 WebSocket 來替代 HTTP?Http 也有 Keep-Alive,如圖隨便抓個 http 的包都能看到 Keep-Alive。

HTTP1.1 默認使用持久連接(persistent connection),在一個 TCP 連接上也可以傳輸多個 Request/Response 消息對,但是 HTTP 的基本模型還是一個 Request 對應一個 Response。這在雙向通信(客戶端要向服務器傳送數據,同時服務器也需要實時的向客戶端傳送信息,一個聊天系統就是典型的雙向通信)時一般會使用這樣幾種解決方案:

  1. 輪詢(polling),輪詢就會造成對網絡和通信雙方的資源的浪費,且非實時。

  2. 長輪詢,客戶端發送一個超時時間很長的 Request,服務器 hold 住這個連接,在有新數據到達時返回 Response,相比#1,佔用的網絡帶寬少了,其他類似。

  3. 長連接,其實有些人對長連接的概念是模糊不清的,我這裏講的其實是 HTTP 的長連接(1)。如果你使用 Socket 來建立 TCP 的長連接(2),那麼,這個長連接(2)跟我們這裏要討論的 WebSocket 是一樣的,實際上 TCP 長連接就是 WebSocket 的基礎,但是如果是 HTTP 的長連接,本質上還是 Request/Response 消息對,仍然會造成資源的浪費、實時性不強等問題。

!

相同點

•都是基於 TCP 的應用層協議

•都使用 Request/Response 模型進行連接的建立

•在連接的建立過程中對錯誤的處理方式相同,在這個階段 WS 可能返回和 HTTP 相同的返回碼

•都可以在網絡中傳輸數據

不同點

•WS 使用 HTTP 來建立連接,但是定義了一系列新的 header 域,這些域在 HTTP 中並不會使用

•WS 的連接不能通過中間人來轉發,它必須是一個直接連接

•WS 連接建立之後,通信雙方都可以在任何時刻向另一方發送數據

•WS 連接建立之後,數據的傳輸使用幀來傳遞,不再需要 Request 消息

•WS 的數據幀有序

二、websocket 握手

出於兼容性的考慮,WS 的握手使用 HTTP 來實現,客戶端的握手消息就是一個「普通的,帶有 Upgrade 頭的,HTTP Request 消息」。所以這一個小節到內容大部分都來自於 RFC2616,這裏只是它的一種應用形式,下面是 RFC6455 文檔中給出的一個客戶端握手消息示例:


    GET /chat HTTP/1.1            //1
    Host: server.example.com   //2
    Upgrade: websocket            //3
    Connection: Upgrade            //4
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==            //5
    Origin: http://example.com            //6
    Sec-WebSocket-Protocol: chat, superchat            //7
    Sec-WebSocket-Version: 13            //8

可以看到,前兩行跟 HTTP 的 Request 的起始行一模一樣,而真正在 WS 的握手過程中起到作用的是下面幾個 header 域。

  1. Upgrade:upgrade 是 HTTP1.1 中用於定義轉換協議的 header 域。它表示,如果服務器支持的話,客戶端希望使用現有的「網絡層」已經建立好的這個「連接(此處是 TCP 連接)」,切換到另外一個「應用層」(此處是 WebSocket)協議。

  2. Connection:HTTP1.1 中規定 Upgrade 只能應用在「直接連接」中,所以帶有 Upgrade 頭的 HTTP1.1 消息必須含有 Connection 頭,因爲 Connection 頭的意義就是,任何接收到此消息的人(往往是代理服務器)都要在轉發此消息之前處理掉 Connection 中指定的域(不轉發 Upgrade 域)。

如果客戶端和服務器之間是通過代理連接的,那麼在發送這個握手消息之前首先要發送 CONNECT 消息來建立直接連接。

  1. Sec-WebSocket-*:第 7 行標識了客戶端支持的子協議的列表(關於子協議會在下面介紹),第 8 行標識了客戶端支持的 WS 協議的版本列表,第 5 行用來發送給服務器使用(服務器會使用此字段組裝成另一個 key 值放在握手返回信息裏發送客戶端)。

  2. Origin:作安全使用,防止跨站攻擊,瀏覽器一般會使用這個來標識原始域。

如果服務器接受了這個請求,可能會發送如下這樣的返回信息,這是一個標準的 HTTP 的 Response 消息。101 表示服務器收到了客戶端切換協議的請求,並且同意切換到此協議。RFC2616 規定只有 HTTP1.1 及 HHTTP1.1 以上版本的時候才能同意切換。

    HTTP/1.1 101 Switching Protocols //1
    Upgrade: websocket. //2
    Connection: Upgrade. //3
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=  //4
    Sec-WebSocket-Protocol: chat. //5

ws 協議默認使用 80 端口,wss 協議默認使用 443 端口。(和 http 一樣啊:relaxed:)

收發數據幀:

客戶端和服務端都能在任意時候發送數據,(不管是從客戶端到服務端還是相反) 每個數據幀的格式都是:

對報文的詳細解析過程可以參考文章如下:http://www.cnblogs.com/yjf512/archive/2013/02/18/2915171.html

查看資料:

http://www.jianshu.com/p/59b5594ffbb0

http://www.jianshu.com/p/0e5b946880b4

http://www.jianshu.com/p/f666da1b1835

https://developer.mozilla.org/zh-CN/docs/WebSockets/Writing_WebSocket_servers


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章