代码改变世界

mochiweb 源码阅读(九)

2012-07-24 10:06  rhinovirus  阅读(1636)  评论(5编辑  收藏  举报

  今天还是一样,要去驾校练车,早起不用上班,看看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是一个意思,判断是否是对应的数据类型,一通百通,也不重复说了。

  好了,这一篇,就到这里。谢谢大家的耐心阅读,咱们下一篇再见。