本文从官方实例keepalive实例入手,查看源码包/examples/keepalive/keepalive.erl
首先从keepalive:start/1入手,也就是整个项目的启动入口:
-define(LOOP, {?MODULE, loop}).
start(Options = [{port, _Port}]) ->
mochiweb_http:start([{name, ?MODULE}, {loop, ?LOOP} | Options]).
启动函数仅含一个执行语句,直接调用mochiweb_http:start函数。这里需要注意的是宏定含义,替换宏定义,实际传入参数为
[{name,keepalive},{loop,{keepalive,loop}}|Options]
接下来进入mochiweb_http文件,查看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} | {recbuf, undefined | non_negative_integer()}
%% @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) ->
ok = ensure_started(mochiweb_clock),
mochiweb_socket_server:start(parse_options(Options)).
mochiweb_http:start/1首先调用ensure_started(mochiwe_clock)确认开启一个时钟服务器,然后在调用mochiweb_socket_server:start/1前会先调用mochiweb_http:parse_options/1函数,下面先看看parse_option/1函数
-define(DEFAULTS, [{name, ?MODULE},
{port, 8888}]).
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是查找Options中Key为loop的Value值,若存在则返回tuple(),否则返回none,实际执行为
{loop,HttpLoop}={loop,{keepalive,loop}}
第二行:将HttpLoop再嵌套一层外盒Loop={mochiweb_http,loop,[{keepalive,loop}]}.
第三行:删除Options中原有的Key值为loop的元组,然后将{loop,Loop}添加进Options中,实际即为更新Key值为loop的元组
第四行:调用mochilists:defaults/2,查看Options1中所对应的?DEFAULTS默认参数是否已存在初始值,若存在则不做处理,若不存在,则将?DEFAULT默认参数添加进去(?DEFAULT宏定义如上所示)
理解parse_options后,进入mochiweb_socket_server:start/1
start_link(Options) ->
start_server(start_link, parse_options(Options)).
start(Options) ->
case lists:keytake(link, 1, Options) of
{value, {_Key, false}, Options1} ->
start_server(sta