代码改变世界

mochiweb 源码阅读(六)

2012-07-20 00:45  rhinovirus  阅读(2057)  评论(2编辑  收藏  举报

  大家好,最近比较忙,游戏忙着上各个主流的大平台,事情比较多。还记得上次给大家推荐的Erlang的书吗?《Erlang/OTP并发编程实战》这本书在china-pub上已经有卖了,想学Erlang的朋友,可以买一本看看,地址:http://product.china-pub.com/3662181。一不小心又做广告了,呵呵,好书嘛,总是忍不住推荐给大家。

  回到今天的正题,继续和大家分析mochiweb源码,在上一篇,我们总结了下mochiweb_example_deps 这个模块的作用,以及简单介绍了下mochiweb_example的启动。这一篇,我们详细看下启动过程。

  首先,我们看下:mochiweb_example_web:start/1,代码如下:

start(Options) ->
    {DocRoot, Options1} = get_option(docroot, Options),
    Loop = fun (Req) ->
                   ?MODULE:loop(Req, DocRoot)
           end,
    mochiweb_http:start([{name, ?MODULE}, {loop, Loop} | Options1]).

  这里的参数是在 mochiweb_example_sup:web_specs/2 启动 mochiweb_example_web工作进程时传递过来的,也就是WebConfig,详细代码如下:

web_specs(Mod, Port) ->
    P = mochiweb_example_deps:local_path(["priv", "www"]),
    io:format("P = ~p~n", [P]),
    WebConfig = [{ip, {0,0,0,0}},
                 {port, Port},
                 {docroot, P}],
    {Mod,
     {Mod, start, [WebConfig]},
     permanent, 5000, worker, dynamic}.

  好了,知道了这个参数的值,我们继续回到 mochiweb_example_web:start/1 函数:

  {DocRoot, Options1} = get_option(docroot, Options),这一行调用mochiweb_example_web:get_option/2,代码如下:

get_option(Option, Options) ->
    {proplists:get_value(Option, Options), proplists:delete(Option, Options)}.

  这里有2个系统函数,我们先看下:

  函数:proplists:get_value/2,erlang doc地址:http://www.erlang.org/doc/man/proplists.html#get_value-2,如下图:  

  这个函数,相当于 get_value(Key, List, undefined),所以我们重点看下:proplists:get_value/3,从列表中返回值的一个简单的键/值属性。如果从List查找到Key,将返回{Key,Value},该函数返回相应的值,否则返回默认值。

  函数:proplists:delete/2,从List中删除所有和Key相关的项。 erlang doc地址:www.erlang.org/doc/man/proplists.html#delete-2,如下图:

  我们在shell上做些简单的测试,测试结果如下:

  

  好了,弄清楚了mochiweb_example_web:get_option/2函数,我们继续回到mochiweb_example_web:start/1 函数,看如下代码:

    Loop = fun (Req) ->
                   ?MODULE:loop(Req, DocRoot)
           end,

  这段代码也比较简单,定义个匿名函数,传递Req参数,匿名函数中就一行代码,调用本模块中的loop/2函数。这个函数我们先跳过,等真正运行该函数时,我们再回过头来看这个函数,这个函数代码如下:  

loop(Req, DocRoot) ->
    "/" ++ Path = Req:get(path),
    try
        case Req:get(method) of
            Method when Method =:= 'GET'; Method =:= 'HEAD' ->
                case Path of
                    _ ->
                        Req:serve_file(Path, DocRoot)
                end;
            'POST' ->
                case Path of
                    _ ->
                        Req:not_found()
                end;
            _ ->
                Req:respond({501, [], []})
        end
    catch
        Type:What ->
            Report = ["web request failed",
                      {path, Path},
                      {type, Type}, {what, What},
                      {trace, erlang:get_stacktrace()}],
            error_logger:error_report(Report),
            %% NOTE: mustache templates need \ because they are not awesome.
            Req:respond({500, [{"Content-Type", "text/plain"}],
                         "request failed, sorry\n"})
    end.

  继续往下看 mochiweb_example_web:start/1 函数:

mochiweb_http:start([{name, ?MODULE}, {loop, Loop} | Options1]).

  这里调用函数:mochiweb_http:start/1,传递一个列表,这个列表由三部分组成:

  第一部分:{name, ?MODULE},?MODULE为当前模块名称;

  第二部分:{loop, Loop},Loop为上一行代码定义的匿名函数;

  第三部分:由第一行代码返回的元组中的第二个项,也就是:[{ip,{0,0,0,0}},{port,8080}]。

  好了,弄清楚参数,我们就可以看下: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)).

  从注释来看,这个函数的作用是启动一个mochiweb服务器,关于Options参数的说明也很详细。

  好了,这一篇就到这里,从下一篇开始我们将正式进入mochiweb源码。从这个函数来看,mochiweb源码还是比较工整的,代码注释也比较完善,感谢作者为我们奉献这么好的开源项目,来让我们学习。

  最后,谢谢大家的耐心阅读。好梦。