Cowboy 源码分析(二十七)
2012-07-08 12:42 rhinovirus 阅读(1491) 评论(0) 编辑 收藏 举报大家好,从2012-05-15号开始的第一篇Cowboy源码分析,到上一篇2012-07-04的第二十六篇为止,我们已经完整的看完了,Cowboy的启动,处理来自浏览器的请求,响应等整个过程。这这一篇,我们来做个总结。毕竟这是我第一个接触的Erlang开源项目,今天回过头来,从整体上去看这个项目。
首先是cowboy应用的启动,我们从observer上可以看到,当该应用程序启动时,启动进程情况,如下图:
我们右键可以查看该进程的相关信息,这点observer做的还是挺方便的,如下图:
下图为打开的进程信息窗口:
从上面可以很容易的获取一些和该进程相关的信息,比如进程名称,消息队列长度,和该进程连接的进程标识符,以及内存占用的相关数据等等。
我们看到当cowboy程序启动时,会启动cowboy_clock这个模块,关于这个模块的作用我不多说,相信看过之前文章的都能知道。
接下来我们看看cowboy_examples启动,如下图:
下面这张,依然是 cowboy应用的新的情况,我们可以看到附加了许多子进程:
当然,由于启动的进程较多,这里并不能完整的看到,我只截取了部分,大家可以自己运行observer看看。
这里有个注意的地方,我刚开始比较没注意,看下 cowboy_examples_app:start/2 代码:
start(_Type, _Args) -> Dispatch = [ {'_', [ {[<<"websocket">>], websocket_handler, []}, {[<<"eventsource">>], eventsource_handler, []}, {[<<"eventsource">>, <<"live">>], eventsource_emitter, []}, {'_', default_handler, []} ]} ], cowboy:start_listener(my_http_listener, 100, cowboy_tcp_transport, [{port, 8080}], cowboy_http_protocol, [{dispatch, Dispatch}] ), %% cowboy:start_listener(my_https_listener, 100, %% cowboy_ssl_transport, [ %% {port, 8443}, {certfile, "priv/ssl/cert.pem"}, %% {keyfile, "priv/ssl/key.pem"}, {password, "cowboy"}], %% cowboy_http_protocol, [{dispatch, Dispatch}] %% ), cowboy_examples_sup:start_link().
这其实是2个例子的,所以我当时看的时候发现两棵完全一样的树,没注意到是两个例子,这里为了方便分析,我注释掉下面这个例子。
编译,重新运行,这回就明朗多了,呵呵。如下图:
下面我把几处关键代码贴出来,大家就能理解这里所有进程的是如何启动:
代码块一:
-spec start_listener(any(), non_neg_integer(), module(), any(), module(), any()) -> {ok, pid()}. start_listener(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) when is_integer(NbAcceptors) andalso is_atom(Transport) andalso is_atom(Protocol) -> supervisor:start_child(cowboy_sup, child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)).
代码块二:
-spec child_spec(any(), non_neg_integer(), module(), any(), module(), any()) -> supervisor:child_spec(). child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) when is_integer(NbAcceptors) andalso is_atom(Transport) andalso is_atom(Protocol) -> {{cowboy_listener_sup, Ref}, {cowboy_listener_sup, start_link, [ NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts ]}, permanent, 5000, supervisor, [cowboy_listener_sup]}.
代码块三:
-spec start_link(non_neg_integer(), module(), any(), module(), any()) -> {ok, pid()}. start_link(NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) -> MaxConns = proplists:get_value(max_connections, TransOpts, 1024), {ok, SupPid} = supervisor:start_link(?MODULE, []), {ok, ListenerPid} = supervisor:start_child(SupPid, {cowboy_listener, {cowboy_listener, start_link, [MaxConns, ProtoOpts]}, permanent, 5000, worker, [cowboy_listener]}), {ok, ReqsPid} = supervisor:start_child(SupPid, {cowboy_requests_sup, {cowboy_requests_sup, start_link, []}, permanent, 5000, supervisor, [cowboy_requests_sup]}), {ok, _PoolPid} = supervisor:start_child(SupPid, {cowboy_acceptors_sup, {cowboy_acceptors_sup, start_link, [ NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts, ListenerPid, ReqsPid ]}, permanent, 5000, supervisor, [cowboy_acceptors_sup]}), {ok, SupPid}.
重点在代码块三,这里的 SupPid 就是添加到 cowboy_sup 的子进程,而工作进程cowboy_listener,以及监控进程cowboy_requests_sup,监控进程cowboy_acceptors_sup都是连接到 SupPid 进程的子进程。
还有一处添加100个子进程到cowboy_acceptors_sup监控进程的代码如下:
-spec start_link(non_neg_integer(), module(), any(), module(), any(), pid(), pid()) -> {ok, pid()}. start_link(NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts, ListenerPid, ReqsPid) -> supervisor:start_link(?MODULE, [NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts, ListenerPid, ReqsPid]). %% supervisor. -spec init([any()]) -> {'ok', {{'one_for_one', 10, 10}, [{ any(), {atom() | tuple(), atom(), 'undefined' | [any()]}, 'permanent' | 'temporary' | 'transient', 'brutal_kill' | 'infinity' | non_neg_integer(), 'supervisor' | 'worker', 'dynamic' | [atom() | tuple()]}] }}. init([NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts, ListenerPid, ReqsPid]) -> {ok, LSocket} = Transport:listen(TransOpts), Procs = [{{acceptor, self(), N}, {cowboy_acceptor, start_link, [ LSocket, Transport, Protocol, ProtoOpts, ListenerPid, ReqsPid ]}, permanent, brutal_kill, worker, []} || N <- lists:seq(1, NbAcceptors)], {ok, {{one_for_one, 10, 10}, Procs}}.
好了,当cowboy_examples启动时,关于进程启动的这块,我们总结完了,下一篇我们看看处理用户请求的这块吧。
谢谢大家。
本文基于署名-非商业性使用 3.0许可协议发布,欢迎转载,演绎,但是必须保留本文的署名rhinovirus(包含链接http://www.cnblogs.com/rhinovirus/),且不得用于商业目的。如您有任何疑问或者授权方面的协商,请与我联系。