mochiweb 源码阅读(七)
2012-07-22 00:35 rhinovirus 阅读(1763) 评论(0) 编辑 收藏 举报早上去公司待了半天,回来时,雨正大,虽然媳妇早上提前把伞塞我包里,但是小伞还是顶不住激情澎湃的大雨,到家已经是落汤鸡了。不过,还是蛮喜欢雨后的安静。虽然小区楼下蛙声不断,但还是蛮适合看书,Coding的。
上一篇文章最后,提到了mochiweb_http:start/1函数,这一篇,我们继续往下看:
%% @spec start(Options) -> ServerRet %% Options = [option()] %% Option = {name, atom()} | {ip, string() | tuple()} | {backlog, integer()} %% | {nodelay, boolean()} | {acceptor_pool_size, integer()} %% | {ssl, boolean()} | {profile_fun, undefined | (Props) -> ok} %% | {link, false} %% @doc Start a mochiweb server. %% profile_fun is used to profile accept timing. %% After each accept, if defined, profile_fun is called with a proplist of a subset of the mochiweb_socket_server state and timing information. %% The proplist is as follows: [{name, Name}, {port, Port}, {active_sockets, ActiveSockets}, {timing, Timing}]. %% @end start(Options) -> mochiweb_socket_server:start(parse_options(Options)).
上一篇,我们提到传递进来的参数的值为:
< Options = [{name,mochiweb_example_web},
{loop,#Fun<dbg_ieval.9.56107335>},
{ip,{0,0,0,0}},
{port,8080}]
这里我们首先看下 mochiweb_http:parse_options/1 函数:
parse_options(Options) -> {loop, HttpLoop} = proplists:lookup(loop, Options), Loop = {?MODULE, loop, [HttpLoop]}, Options1 = [{loop, Loop} | proplists:delete(loop, Options)], mochilists:set_defaults(?DEFAULTS, Options1).
这个函数的作用是解析配置项,函数:proplists:lookup/2,返回List中第一个和Key相关的项,如果存在的话,否则返回none。对于在List中的一个原子A,元组{A, true}是与A相关的项 。erlang doc地址:http://www.erlang.org/doc/man/proplists.html#lookup-2,如下图:
我们可以在shell中测试下这个函数,测试结果如下:
好了,搞清楚这个函数,我们就可以继续往下看了:
parse_options(Options) -> {loop, HttpLoop} = proplists:lookup(loop, Options), Loop = {?MODULE, loop, [HttpLoop]}, Options1 = [{loop, Loop} | proplists:delete(loop, Options)], mochilists:set_defaults(?DEFAULTS, Options1).
剩下就没啥难度了,大家一样就能看明白了,第三行从Options中删除旧的loop项,增加一个新的loop项。我们看下最后一行,这里调用 mochilists:set_defaults/2 函数,其中?DEFAULTS定义如下:
-define(DEFAULTS, [{name, ?MODULE},
{port, 8888}]).
mochilists:set_defaults/2 函数代码如下:
%% @spec set_defaults([{Key::term(), Value::term()}], Proplist::list()) -> list() %% %% @doc Return new Proplist with {Key, Value} set if not is_defined(Key, Proplist). set_defaults(DefaultProps, Proplist) -> lists:foldl(fun set_default/2, Proplist, DefaultProps).
这里对DefaultProps的每一项调用mochilists:set_default/2 函数,Proplist作为该函数的第二个参数。lists:foldl/3这个函数,我们在这里系列的第二篇文章讲到过,大家可以翻看mochiweb 源码阅读(二)回忆下。mochilists:set_default/2 函数代码如下:
%% @spec set_default({Key::term(), Value::term()}, Proplist::list()) -> list() %% %% @doc Return new Proplist with {Key, Value} set if not is_defined(Key, Proplist). set_default({Key, Value}, Proplist) -> case is_defined(Key, Proplist) of true -> Proplist; false -> [{Key, Value} | Proplist] end.
这个函数,首先调用 mochilists:is_defined/2 函数,代码如下:
%% @spec is_defined(Key::term(), Proplist::list()) -> bool() %% %% @doc Returns true if Propist contains at least one entry associated %% with Key, otherwise false is returned. is_defined(Key, Proplist) -> lists:keyfind(Key, 1, Proplist) =/= false.
这个函数就一行代码,如果Prolist中的元素的第一个项为Key,则返回该元素,否则返回false,示例如下:
注意这里对L1列表调用的结果,为false。
我们整理下mochilists:set_defaults/2 函数调用的过程,如下:
------------------------------------------------------- set_defaults(DefaultProps, Proplist) ------------------------------------------------------- < DefaultProps = [{name,mochiweb_http},{port,8888}] < Proplist = [{loop,{mochiweb_http,loop, [#Fun<mochiweb_example_web.0.8815963>]}}, {name,mochiweb_example_web}, {ip,{0,0,0,0}}, {port,8080}] ------------------------------------------------------- set_default({Key, Value}, Proplist) ------------------------------------------------------- < Key = name < Value = mochiweb_http < Proplist = [{loop,{mochiweb_http,loop, [#Fun<mochiweb_example_web.0.8815963>]}}, {name,mochiweb_example_web}, {ip,{0,0,0,0}}, {port,8080}] ------------------------------------------------------- set_default({Key, Value}, Proplist) ------------------------------------------------------- < Key = port < Value = 8888 < Proplist = [{loop,{mochiweb_http,loop, [#Fun<mochiweb_example_web.0.8815963>]}}, {name,mochiweb_example_web}, {ip,{0,0,0,0}}, {port,8080}]
通过分析代码的执行过程,我们能够知道,这三个函数的作用,就是检查用户传递进来的配置列表Proplist中,是否存在默认配置列表DefaultProps中的项,如果不存在,则使用默认配置。
好了,理解完这个函数,mochiweb_http:parse_options/1 函数也就讲完了,我们继续回到调用这个函数的地方,如下:
start(Options) ->
mochiweb_socket_server:start(parse_options(Options)).
函数 mochiweb_socket_server:start/1 代码如下:
start(Options) -> case lists:keytake(link, 1, Options) of {value, {_Key, false}, Options1} -> start_server(start, parse_options(Options1)); _ -> %% TODO: https://github.com/mochi/mochiweb/issues/58 %% [X] Phase 1: Add new APIs (Sep 2011) %% [_] Phase 2: Add deprecation warning %% [_] Phase 3: Change default to {link, false} and ignore link %% [_] Phase 4: Add deprecation warning for {link, _} option %% [_] Phase 5: Remove support for {link, _} option start_link(Options) end.
好了,这一篇就到这里。下一篇我们继续从这个函数往下看。
也不知道明天天气咋样,报了那么久的驾照培训,明天是第一天上车,希望明天一切顺利,大家好梦。
本文基于署名-非商业性使用 3.0许可协议发布,欢迎转载,演绎,但是必须保留本文的署名rhinovirus(包含链接http://www.cnblogs.com/rhinovirus/),且不得用于商业目的。如您有任何疑问或者授权方面的协商,请与我联系。