今天還是一樣,要去駕校練車,早起不用上班,看看mochiweb源碼,繼續和大家分享。昨天有個函數給跳過了,今天看了下,也有不少知識點,還是補下吧,函數:mochiweb_socket_server:parse_options/1,完整代碼如下:
parse_options(State=#mochiweb_socket_server{}) -> State; parse_options(Options) -> parse_options(Options, #mochiweb_socket_server{}).
如果傳遞的是配置是#mochiweb_socket_server{}記錄類型,則直接返回,否則調用mochiweb_socket_server:parse_options/2,傳遞配置列表,以及#mochiweb_socket_server{},這里Options的值為:
< Options = [{loop,{mochiweb_http,loop,
[#Fun<mochiweb_example_web.0.8815963>]}},
{name,mochiweb_example_web},
{ip,{0,0,0,0}},
{port,8080}]
我們來逐個分支分析下:
分支一(配置列表為[]的處理):
parse_options([], State) ->
State;
如果配置項為[],返回State;
分支二(關於name部分的處理):
parse_options([{name, L} | Rest], State) when is_list(L) -> Name = {local, list_to_atom(L)}, parse_options(Rest, State#mochiweb_socket_server{name=Name}); parse_options([{name, A} | Rest], State) when A =:= undefined -> parse_options(Rest, State#mochiweb_socket_server{name=A}); parse_options([{name, A} | Rest], State) when is_atom(A) -> Name = {local, A}, parse_options(Rest, State#mochiweb_socket_server{name=Name}); parse_options([{name, Name} | Rest], State) -> parse_options(Rest, State#mochiweb_socket_server{name=Name});
這四個分支是跟{name, ?}相關的,當?分別為:list,undefined,atom,其他值,這四種情況分別調用這四個分支其中一個,我們看下這里用到了哪些系統函數:
函數:is_list/1,erlang doc 地址:http://www.erlang.org/doc/man/erlang.html#is_list-1,如下圖:
如果Term是一個零個或多個元素的列表返回true,否則返回false。
函數:list_to_atom/1,erlang doc 地址:http://www.erlang.org/doc/man/erlang.html#list_to_atom-1,如下圖:
返回字符串的文本表示原子。
注意:這里其實是不嚴謹的,雖然字符串是特殊的列表,但是如果傳遞[a, b,c]這樣的列表,它是滿足is_list/1為true的,但是調用list_to_atom/1卻會拋出異常的。
函數:is_atom/1,erlang doc 地址:http://www.erlang.org/doc/man/erlang.html#is_atom-1,如下圖:
如果Term是一個原子,返回true,否則返回false。
我在shell做了些測試例子,如下圖:
注意拋異常的部分。關於分支二,剩下就是修改記錄中name字段的值了,很簡單,我們繼續往下看。
分支三(關於port部分的處理):
parse_options([{port, L} | Rest], State) when is_list(L) -> Port = list_to_integer(L), parse_options(Rest, State#mochiweb_socket_server{port=Port}); parse_options([{port, Port} | Rest], State) -> parse_options(Rest, State#mochiweb_socket_server{port=Port});
這里先看下系統函數:list_to_integer/1,erlang doc 地址:http://www.erlang.org/doc/man/erlang.html#list_to_integer-1,如下圖:
根據字符串的文本返回返回一個整數。失敗:如果字符串包含不是數字的文本,則會提示badarg。
測試如下:
剩下就是修改記錄中port字段的值;
分支四(ip部分的處理):
parse_options([{ip, Ip} | Rest], State) -> ParsedIp = case Ip of any -> any; Ip when is_tuple(Ip) -> Ip; Ip when is_list(Ip) -> {ok, IpTuple} = inet_parse:address(Ip), IpTuple end, parse_options(Rest, State#mochiweb_socket_server{ip=ParsedIp});
看下系統函數:is_tuple/1,erlang doc 地址:http://www.erlang.org/doc/man/erlang.html#is_tuple-1,如下圖:
如果Term為元組類型,則返回true,否則返回false。
系統函數:inet_parse:address/1,erlang doc 地址:http://www.erlang.org/doc/man/inet.html,這個模塊我沒找到,只在上面那個地址看到部分例子,如下圖:
大概就是把一個字符串格式的ip地址,轉為{ok, {192,168,1,1}}類似這樣的格式。
測試例子如下:
剩下就是和之前沒什么區別,修改對應記錄中字段的值,這里是ip字段。
分支五:
parse_options([{loop, Loop} | Rest], State) -> parse_options(Rest, State#mochiweb_socket_server{loop=Loop}); parse_options([{backlog, Backlog} | Rest], State) -> parse_options(Rest, State#mochiweb_socket_server{backlog=Backlog}); parse_options([{nodelay, NoDelay} | Rest], State) -> parse_options(Rest, State#mochiweb_socket_server{nodelay=NoDelay});
這部分分支,直接就是修改對應記錄中字段的值,很簡單,我們直接跳過。
分支六:
parse_options([{acceptor_pool_size, Max} | Rest], State) -> MaxInt = ensure_int(Max), parse_options(Rest, State#mochiweb_socket_server{acceptor_pool_size=MaxInt});
這里首先調用函數 mochiweb_socket_server:ensure_int/1:
ensure_int(N) when is_integer(N) -> N; ensure_int(S) when is_list(S) -> list_to_integer(S).
很簡單,如果是數字類型,則直接返回,如果是文本為數字的字符串,則轉為數字后返回。
由於剩下分支邏輯都比較簡單,我把剩余分支都貼出來,只講不同的部分:
parse_options([{max, Max} | Rest], State) -> error_logger:info_report([{warning, "TODO: max is currently unsupported"}, {max, Max}]), MaxInt = ensure_int(Max), parse_options(Rest, State#mochiweb_socket_server{max=MaxInt}); parse_options([{ssl, Ssl} | Rest], State) when is_boolean(Ssl) -> parse_options(Rest, State#mochiweb_socket_server{ssl=Ssl}); parse_options([{ssl_opts, SslOpts} | Rest], State) when is_list(SslOpts) -> SslOpts1 = [{ssl_imp, new} | proplists:delete(ssl_imp, SslOpts)], parse_options(Rest, State#mochiweb_socket_server{ssl_opts=SslOpts1}); parse_options([{profile_fun, ProfileFun} | Rest], State) when is_function(ProfileFun) -> parse_options(Rest, State#mochiweb_socket_server{profile_fun=ProfileFun}).
首先是:error_logger:info_report/1,erlang doc 地址:http://www.erlang.org/doc/man/error_logger.html#info_report-1,如下圖:
發送一個標准信息報告事件的錯誤記錄。事件處理的標准事件處理程序。其實就是使用sasl往shell顯示事件信息。
函數:is_boolean/1,is_function/1,和之前講過的is_list/1是一個意思,判斷是否是對應的數據類型,一通百通,也不重復說了。
好了,這一篇,就到這里。謝謝大家的耐心閱讀,咱們下一篇再見。