對Socket的{active, true}參數進行一些測試

以前不是很瞭解Erlang網絡編程中流量控制,現在做一下筆記。

Erlang中Socket設置了{active, true}之後,接收到的網絡消息會通過{tcp, Socket, Data}的格式主動發送給進程,這樣做有個弊處就是沒有做流量控制。要是有個客戶端瘋狂發包過來,服務器不做處理就等着堆溢出。
在《Programming Erlang》的14.2裏面,介紹可以使用 {active, once} 來做控制。


{ok, Listen} = gen_tcp:listen(Port, [..,{active, once}...]),
{ok, Socket} = gen_tcp:accept(Listen),
loop(Socket).
loop(Socket) ->
receive
{tcp, Socket, Data} ->
... do something with the data ...
%% when you're ready enable the next message
inet:setopts(Sock, [{active, once}]),
loop(Socket);
{tcp_closed, Socket} ->
...
end.


不過[url="http://mryufeng.iteye.com/"]鋒爺[/url]認爲這種做法會影響性能,因爲每次接收信息都要調用一次 inet:setopts(Sock, [{active, once}]) 。

既然這樣,那就先使用{active, true},如果判斷到接收到的消息包太多,再改成 {active, once}。我寫了個簡單的代碼:


listen_socket(Socket, Mode) ->
receive
{tcp, Socket, Bin} ->
process_req(Bin),
{message_queue_len, MsgQueueSize} = erlang:process_info(self(), message_queue_len),
if
(MsgQueueSize > 500) and (Mode =:= active_true) ->
io:format("Queue size is ~p~n", [MsgQueueSize]),
inet:setopts(Socket, [{active, once}]),
listen_socket(Socket, active_once);
(MsgQueueSize < 10) and (Mode =:= active_once) ->
io:format("Queue size is ~p~n", [MsgQueueSize]),
inet:setopts(Socket, [{active, true}]),
listen_socket(Socket, active_true);
true ->
io:format("Queue size is ~p~n", [MsgQueueSize]),
listen_socket(Socket, Mode)
end;


判斷當前進程消息隊列的數量,大於500時被動接收,小於10時再次改爲主動接收。
打開服務器後,客戶端使用阻塞方式({active, false})連續來發送2000個消息包給服務器,很快服務器端的消息累計達到500以上,此時{active, once}被設置,數據包開始在系統底層堆積,很快就看到客戶端的gen_tcp:send調用被阻塞,直到服務器設置{active, true}後,堆積的消息被加載到內存消息隊列中,gen_tcp:send恢復正常發送。
可見當{active, once}被設置後,若消息隊列中還有數據包,則系統底層的數據包會被堆積,起到了流量控制的作用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章