知道了怎麼握手隻是讓用戶端和伺服器建立連接配接而已,WebSocket真正麻煩的地方是在資料的傳輸上!為了環保,它使用了特定格式的資料幀,這個資料幀需要自己去解析(當然也有别人編寫好的庫可以用)。雖然官方文檔描述的很詳細,但是看起來還是蛋疼。
當用戶端向伺服器發送一個資料時伺服器收到一個資料幀,比如下面的程式:
===============================================================
這裡是直接把接收到的資料輸出了,得到這樣一個東西
這就是一個完整的資料幀,直接的16進制資料我們當然無法直接閱讀,需要按照資料幀的格式把它裡面的資料取出來才行。對于這個資料幀,官方文檔提供了一個結構圖
光拿出這個實在很難看懂,頂部數字用十進制而不是八進制太讓人蛋疼了。當然官方文檔在後面的描述中也有詳細介紹,看完後再回頭來看圖表才能看明白。其實WebSocket目前還不太完善,很多實驗性的東西,是以完全按照官方文檔來了解是蛋疼的。這裡就說我自己的了解。
現在再看左上角上面的圖示,左上角的四個小列,也就是4位,第一位是FIN,後面三位是RSV1到3。官方文檔上說RSV是預留的空間,正常為0,這就意味着,正常情況下他們可以當做0填充,那麼前4位隻有第一位的FIN需要設定,FIN表示幀結束,由于這篇中它不重要就不特别介紹了。接着後面的四位是儲存opcode的值,這個opcode是辨別資料類型的。這樣資料的第一個位元組我們就能了解它的含義了,看上面16進制的資料的第一個位元組81換成二進制是1000001,第一個1是FIN的值,最後一個1是opcode的值。
接着是第二個位元組的資料,它由1位的MASK和7位的PayloadLen組成,MASK辨別這個資料幀的資料是否使用掩碼,PayloadLen表示資料部分的長度。但是PayloadLen隻有7位,換成無符号整型的話隻有0到127的取值,這麼小的數值當然無法描述較大的資料,是以規定當資料長度小于或等于125時候它才作為資料長度的描述,如果這個值為126,則時候後面的兩個位元組來儲存儲存資料長度,如果為127則用後面八個位元組來儲存資料長度。是以上面的圖檔第一行的最右側那塊和第二行看起來有些頹然。從我們的示例資料來看,第二個位元組的8C中80是最高位為1,這意味着MASK為1,後面的C表示這個資料部分有12個位元組。
再接着是上面圖表中的MaskingKey,它占四個位元組,儲存掩碼的實體部分。但是隻有在前面的MASK被設定為1時候才存在這個資料,否則不使用掩碼也就沒有這個資料了。看我們的示例資料,由于前面的MASK為1,是以3到6位元組的“79 77 3d 41”是資料的掩碼實體。
最後是資料部分,如果掩碼存在,那麼所有資料都需要與掩碼做一次異或運算,四個位元組的掩碼與所有資料位元組輪流發生性關系。如果不存在掩碼,那麼後面的資料就可以直接使用。
這樣資料幀就解析完了。下面是我寫的資料幀解析的程式,請不要吐槽代碼沒優化
既然有了解析程式,那麼我們就可以把上面執行個體伺服器端的onmessage方法修改一下
這樣伺服器接收用戶端穿過了的資料就沒問題了。嘛,這篇文章就隻說接收,至于從伺服器發送到客戶的情況會有更複雜的情況出現,咱下一篇再說。