mochiweb 源碼閱讀(九)


  今天還是一樣,要去駕校練車,早起不用上班,看看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/1is_function/1,和之前講過的is_list/1是一個意思,判斷是否是對應的數據類型,一通百通,也不重復說了。

  好了,這一篇,就到這里。謝謝大家的耐心閱讀,咱們下一篇再見。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM