mochiweb 源码阅读(十一)
2012-07-29 02:06 rhinovirus 阅读(1651) 评论(0) 编辑 收藏 举报大家好,今天周六,继续接着上一篇,跟大家分享mochiweb源码。上一篇,最后我们看到了mochiweb_socket_server:listen/3函数:
listen(Port, Opts, State=#mochiweb_socket_server{ssl=Ssl, ssl_opts=SslOpts}) -> case mochiweb_socket:listen(Ssl, Port, Opts, SslOpts) of {ok, Listen} -> {ok, ListenPort} = mochiweb_socket:port(Listen), {ok, new_acceptor_pool( Listen, State#mochiweb_socket_server{listen=Listen, port=ListenPort})}; {error, Reason} -> {stop, Reason} end.
我们看下最后一行调用mochiweb_socket_server:new_acceptor_pool/2函数,并且返回{ok, 该函数的返回结果},该函数完整代码如下:
new_acceptor_pool(Listen, State=#mochiweb_socket_server{acceptor_pool=Pool, acceptor_pool_size=Size, loop=Loop}) -> F = fun (_, S) -> Pid = mochiweb_acceptor:start_link(self(), Listen, Loop), sets:add_element(Pid, S) end, Pool1 = lists:foldl(F, Pool, lists:seq(1, Size)), State#mochiweb_socket_server{acceptor_pool=Pool1}.
这个函数,首先定义匿名函数F,这个匿名函数,接受2个参数,其中第一个参数丢弃了,另一个参数为S;接着我们看下第一行,调用mochiweb_acceptor:start_link/3函数,并返回进程标识Pid,接着调用系统函数 sets:add_element/2,我们先看下这个系统函数,erlang doc 地址:http://www.erlang.org/doc/man/sets.html#add_element-2,如下图:
返回一个新的set由Set1插入Element形成。
好了,弄清楚匿名函数的逻辑,这里我们先不关注mochiweb_acceptor:start_link/3函数具体内部逻辑,现在只要知道它会返回一个进程标识符就可以了。
我们继续往下看:
Pool1 = lists:foldl(F, Pool, lists:seq(1, Size)),
这里首先调用lists:seq/2函数,产生1到Size的列表。这里:acceptor_pool_size=Size=16,取的是mochiweb_socket_server记录acceptor_pool_size字段的默认值。然后依次对这个列表调用匿名函数F,并传递列表中的元素值,以及Pool变量,这里:acceptor_pool=Pool=sets:new(),这里也是取的mochiweb_socket_server记录acceptor_pool字段的默认值。注意:之前匿名函数F的第一个参数为丢弃的值:_,表示这里并不需要这个元素的值,只是循环调用这个匿名函数Size次,并且每次都是在之前的set基础上增加新的Element,并返回。
最后把State#mochiweb_socket_server字段acceptor_pool的值修改为返回的最新的set类型的变量Pool1。
好了,到目前为止,我们已经弄明白了new_acceptor_pool函数,回过头来,我们看下之前没有详细看的mochiweb_acceptor:start_link/3函数:
start_link(Server, Listen, Loop) ->
proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop]).
这个函数很简单,就一行逻辑,调用系统函数:proc_lib:spawn_link/3,erlang doc 地址:http://www.erlang.org/doc/man/proc_lib.html#spawn_link-3,如下图:
这个函数的作用和erlang模块下的spawn_link功能类似,都是初始化一个进程来执行指定模块下的指定函数。关于用proc_lib创建的进程有什么与众不同,这里不打算多说,大家可以参考坚强2002同学的,这篇文章:[Erlang 0017]Erlang/OTP基础模块 proc_lib。
接下来我们就可以看下mochiweb_acceptor:init/3函数,完整代码如下:
init(Server, Listen, Loop) -> T1 = now(), case catch mochiweb_socket:accept(Listen) of {ok, Socket} -> gen_server:cast(Server, {accepted, self(), timer:now_diff(now(), T1)}), call_loop(Loop, Socket); {error, closed} -> exit(normal); {error, timeout} -> init(Server, Listen, Loop); {error, esslaccept} -> exit(normal); Other -> error_logger:error_report( [{application, mochiweb}, "Accept failed error", lists:flatten(io_lib:format("~p", [Other]))]), exit({error, accept_failed}) end.
接下来,我们来详细看下这个函数的具体逻辑:
T1 = now()
这一行,调用系统函数erlang:now/0,erlang doc 地址:http://www.erlang.org/doc/man/erlang.html#now-0,如下图:
测试如下:
好了,这一篇就到这里,下一篇,我们将从mochiweb_socket:accept/1继续往下看。
最后,谢谢大家的支持,晚安。
本文基于署名-非商业性使用 3.0许可协议发布,欢迎转载,演绎,但是必须保留本文的署名rhinovirus(包含链接http://www.cnblogs.com/rhinovirus/),且不得用于商业目的。如您有任何疑问或者授权方面的协商,请与我联系。