Erlang網絡編程

一、Socket消息模式
Erlang的socket有3種消息接收模式:active、passive和active once;
可以在gen_tcp:connect/3或gen_tcp:listen/2裏設置{active, true | false |once}來實現,也可以用inet:setopts/2來動態設置。

這3種模式的區別是:
1. active(主動消息接收):非阻塞。當數據到達時系統會向控制進程發送{tcp, Socket, Data}消息。控制進程無法控制消息流;
2. passive(被動消息接收):阻塞。控制進程必須主動調用recv()來接收消息。可以控制消息流;
3. active once(混合消息接收):半阻塞。這種模式是主動的,但僅針對一個消息在控制進程收到一個消息後,必須顯式調用inet:setopts(Socket, [{active, once}])來重新接收下一個消息。可以進行流量控制。這種模式相對於被動模式來說,優點是可以同時等待多個socket的數據。

二、數據封包處理
1、{active, false} 方式通過 gen_tcp:recv(Socket, Length) -> {ok, Data} | {error, Reason} 來接收。
2、{active, true} 方式以消息形式{tcp, Socket, Data} | {tcp_closed, Socket} 主動投遞給線程。

第一種方式:
gen_tcp:recv/2,3,如果封包的類型是{packet, raw}或者{packet,0},就需要顯式的指定長度,否則封包的長度是對端決定的,長度只能設置爲0。如果長度Length設置爲0,gen_tcp:recv/2,3會取出Socket接收緩衝區所有的數據
第二種方式:
緩存區有多少數據,都會全部以消息{tcp, Socket, Data} 投遞給線程。

3、socket的選項裏面的{packet,0}和{packet,raw}的區別
{packet,2} erlang處理2字節大端包頭;
{packet,4} erlang處理4字節大端包頭;
{packet,0} erlang不負責拆包,用戶自己處理;
{packet,raw} erlang不負責拆包,用戶自己處理,t可以處理icmp之類的特殊包。

4、粘包處理
當client在極短的時間內發送多個包給server,這時server在接收數據的時候可能發生連包問題,就一次性接收這幾個包的數據,導致數據都粘連在一起。
自己處理粘包的時候,使用{active, N}(還沒有到被動模式)和{active, true}選項的時候,在handle_info({tcp,Socket,Data}裏面需要好好處理下粘包,

三、WS幀數據
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
byte1 
(1)Fin代表數據是否結束,WebSocket會把較大的數據分成片發送,最後一片數據的Fin爲1,代表數據片完結 
(2)RSV1-RSV3是保留爲,一般爲0 
(3)最後4bit代表Opcode,OpCode用來指示數據幀的類型。WebSocket的幀分爲兩大類型,數據幀和控制幀。 
0x0 代表連續幀,也就因爲這該幀數據是分片數據中的一片,並不是完整數據 
0x1 代表數據是文本內容 
0x2 代表數據時二進制流 
0x3-0x7 保留給日後的非控制幀使用 
0x8 代表該數據時一個關閉命令通知(下面會解釋關閉) 
0x9 代表Ping幀(同樣下面會解釋Ping) 
0xA 代表Pong幀 
0xB-0xF 保留給日後的控制幀使用
byte2 
(1)Mask代表發來的幀中的數據,是否經過掩碼處理,1爲true,0爲false,一般在客戶端發給服務器端的數據中,該值都是1,也就是經過掩碼處理,服務器發往客戶端的不用掩碼。(注意,所謂的客戶端,服務端是相對的,接收WebSocket連接的那一端,也就是上面提到的回發加密處理的那一端是服務器端。這也解釋了,爲什麼我們要遵循WebSocket標準來進行握手,否則客戶端怎麼知道自己發的數據得要掩碼處理呢) 
(2)後面7位代表數據幀的數據長度或者是一個長度指示。我自己理解爲是一個長度預判。當數據長度不超過125字節時,該值就是實際的數據長度,當長度在126~65535時,該值爲固定的126,超過65535,該值固定爲127
byte3~byte4 
當Payload len = 126時,保存的是該幀數據的16位真實長度
byte3~byte10 
當Payload len = 127時,保存的是該幀數據64位的真實長度
注意,如果長度不超過125,那麼byte3~byte10就不代表數據長度了,也就是說不會預留給數據長度用,而是給後續的幀頭信息使用,後續幀頭的字節信息左移
byte11~byte14 
這4個字節代表掩碼值,用客戶端指定,每個包都不一樣,只有經過掩碼值的解碼處理,才能獲得正確的數據
由此可以看到,WebSocket的消息封包,服務器端至少需要2個字節,客戶端至少6個字節。

發佈了41 篇原創文章 · 獲贊 10 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章