标签:
上两篇分别用两种方式启动了inets中的httpd,其实本质一样的;下面简单分析一下过程,函数粒度的介绍。
1,下面是application inets的代码目录,虽然ftp、tftp、http_client、http_lib、http_server、inets_app在这目录中并列,其实inets_app扮演顶层控制角色;
只有inets_app是一个application,而其他都是module---application的一部分并且需要application启动和管理。
[root@james src]# pwd /root/otp_src_17.5/lib/inets/src [root@james src]# l total 32 drwxrwxr-x 2 2004 uucp 4096 Mar 31 20:32 ftp drwxrwxr-x 2 2004 uucp 4096 Mar 31 20:32 http_client drwxrwxr-x 2 2004 uucp 4096 Mar 31 20:32 http_lib drwxrwxr-x 2 2004 uucp 4096 Mar 31 20:32 http_server drwxrwxr-x 2 2004 uucp 4096 Mar 31 20:32 inets_app -rw-rw-r-- 1 2004 uucp 1083 Mar 31 20:32 Makefile -rw-rw-r-- 1 2004 uucp 126 Mar 31 20:32 subdirs.mk drwxrwxr-x 2 2004 uucp 4096 Mar 31 20:32 tftp [root@james src]#
2,下面是inets_app的目录和文件:
[root@james inets_app]# l total 76 -rw-rw-r-- 1 2004 uucp 838 Mar 31 20:32 inets_app.erl -rw-rw-r-- 1 2004 uucp 3216 Mar 31 20:32 inets.app.src -rw-rw-r-- 1 2004 uucp 812 Mar 31 20:32 inets.appup.src -rw-rw-r-- 1 2004 uucp 126 Mar 31 20:32 inets.config -rw-rw-r-- 1 2004 uucp 15651 Mar 31 20:32 inets.erl -rw-rw-r-- 1 2004 uucp 1591 Mar 31 20:32 inets_internal.hrl -rw-rw-r-- 1 2004 uucp 1215 Mar 31 20:32 inets.mk -rw-rw-r-- 1 2004 uucp 11503 Mar 31 20:32 inets_regexp.erl -rw-rw-r-- 1 2004 uucp 2217 Mar 31 20:32 inets_service.erl -rw-rw-r-- 1 2004 uucp 3870 Mar 31 20:32 inets_sup.erl -rw-rw-r-- 1 2004 uucp 11277 Mar 31 20:32 inets_trace.erl -rw-rw-r-- 1 2004 uucp 3256 Mar 31 20:32 Makefile [root@james inets_app]#
以下几个文件比较重要,控制着整个application的启动停止:
3,简单说说inets.erl,这里没有复杂的东西也不是最重要的:
41 %%-------------------------------------------------------------------- 42 %% Function: start([, Type]) -> ok 43 %% 44 %% Type = permanent | transient | temporary 45 %% 46 %% Description: Starts the inets application. Default type 47 %% is temporary. see application(3) 48 %%-------------------------------------------------------------------- 49 start() -> 50 application:start(inets). 51 52 start(Type) -> 53 application:start(inets, Type).
启动函数start,本质调用了inets_app.erl中的代码;
91 %%-------------------------------------------------------------------- 92 %% Function: stop() -> ok 93 %% 94 %% Description: Stops the inets application. 95 %%-------------------------------------------------------------------- 96 stop() -> 97 application:stop(inets). 98 ...... 108 stop(stand_alone, Pid) -> 109 true = exit(Pid, shutdown), 110 ok; 111 112 stop(Service, Pid) -> 113 Module = service_module(Service), 114 call_service(Module, stop_service, Pid).
停止函数stop,也是调用了inets_app.erl中的函数,或者使用内嵌函数exit shutdown进程。(这里略过)
4,接下来说inets_app.erl的实现:
26 start(_Type, _State) ->
27 inets_sup:start_link().
28
29 stop(_State) ->
30 ok.
实现很简单,就是调用inets_sup.erl中的函数。
5, 下面说inets_sup.erl中的函数start_link函数和回调函数init:
34 %%%========================================================================= 35 %%% External functions 36 %%%========================================================================= 37 start_link() -> 38 supervisor:start_link({local, ?MODULE}, ?MODULE, []). 39 40 %%%========================================================================= 41 %%% Supervisor callback 42 %%%========================================================================= 43 init([]) -> 44 SupFlags = {one_for_one, 10, 3600}, 45 Children = children(), 46 {ok, {SupFlags, Children}}. 47
inets_sup.erl的behaviour自然是supervisor,通过supervisor调用start_link时,init作为回调函数(supervisor的设计就是这样)。
SupFlags,是supervisor behaviour的配置参数,在这里就是一个Tuple结构 ------ {one_for_one, 10, 3600},此处略过(OTP相关文档中有介绍supervisor)。
5+,下面详细看children函数,这里信息量最丰富!
51 get_services() -> 52 case (catch application:get_env(inets, services)) of 53 {ok, Services} -> 54 Services; 55 _ -> 56 [] 57 end. 58 59 children() -> 60 Services = get_services(), 61 HttpdServices = [Service || Service <- Services, is_httpd(Service)], 62 HttpcServices = [Service || Service <- Services, is_httpc(Service)], 63 TftpdServices = [Service || Service <- Services, is_tftpd(Service)], 64 [ftp_child_spec(), httpc_child_spec(HttpcServices), 65 httpd_child_spec(HttpdServices), tftpd_child_spec(TftpdServices)]. 66
做个实验,这里很有收获:
原来启动erlang虚拟机时-config inets_httpd18080.config已经被解析(这个解析过程我还没分析,有时间在搞一篇吧),并且从这里获取到。
这样看来,children函数中HttpdServices就是一个Tuple结构,比如{httpd, "/root/inetsConf/18080.conf"}~~~下面看函数httpd_child_spec。
5++,再看httpd_child_spec函数的代码:
87 httpd_child_spec(HttpdServices) -> 88 Name = httpd_sup, 89 StartFunc = {httpd_sup, start_link, [HttpdServices]}, 90 Restart = permanent, 91 Shutdown = infinity, 92 Modules = [httpd_sup], 93 Type = supervisor, 94 {Name, StartFunc, Restart, Shutdown, Type, Modules}. 95
其中StartFunc是supervisor启动worker时需要的Tuple结构,这里HttpdServices作为StartFunc的一个部分。
可以解释一下,httpd_sup是模块,start_link是这个模块的函数,而[HttpdServices]作为这个函数的参数;
很明显,这里并不解析"/root/inetsConf/18080.conf"配置文件,仅作为参数传下去,进入了具体的module(比如http_server)~
6,简单列一下http_server中httpd_sup.erl实现解析参数的代码------使用proplist把文件读了再解析再存储以便后面步骤检索判断,看起来很明白,我就不废话解释了:
89 %%%========================================================================= 90 %%% Supervisor callback 91 %%%========================================================================= 92 init([HttpdServices]) -> 93 ?hdrd("starting", [{httpd_service, HttpdServices}]), 94 RestartStrategy = one_for_one, 95 MaxR = 10, 96 MaxT = 3600, 97 Children = child_specs(HttpdServices, []), 98 {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. 99 ...... 118 child_specs([], Acc) -> 119 Acc; 120 child_specs([{httpd, HttpdService} | Rest], Acc) -> 121 ?hdrd("child specs", [{httpd, HttpdService}]), 122 NewHttpdService = (catch mk_tuple_list(HttpdService)), 123 ?hdrd("child specs", [{new_httpd, NewHttpdService}]), 124 case catch child_spec(NewHttpdService) of 125 {error, Reason} -> 126 ?hdri("failed generating child spec", [{reason, Reason}]), 127 error_msg("Failed to start service: ~n~p ~n due to: ~p~n", 128 [HttpdService, Reason]), 129 child_specs(Rest, Acc); 130 Spec -> 131 ?hdrt("child spec", [{child_spec, Spec}]), 132 child_specs(Rest, [Spec | Acc]) 133 end. 134 135 child_spec(HttpdService) -> 136 {ok, Config} = httpd_config(HttpdService), 137 ?hdrt("child spec", [{config, Config}]), 138 Debug = proplists:get_value(debug, Config, []), 139 AcceptTimeout = proplists:get_value(accept_timeout, Config, 15000), 140 httpd_util:valid_options(Debug, AcceptTimeout, Config), 141 httpd_child_spec(Config, AcceptTimeout, Debug). 142 143 httpd_config([Value| _] = Config) when is_tuple(Value) -> 144 case proplists:get_value(file, Config) of 145 undefined -> 146 case proplists:get_value(proplist_file, Config) of 147 undefined -> 148 httpd_conf:validate_properties(Config); 149 File -> 150 try file:consult(File) of 151 {ok, [PropList]} -> 152 httpd_conf:validate_properties(PropList) 153 catch 154 exit:_ -> 155 throw({error, 156 {could_not_consult_proplist_file, File}}) 157 end 158 end; 159 File -> 160 {ok, File} 161 end. 162 163 httpd_child_spec([Value| _] = Config, AcceptTimeout, Debug) 164 when is_tuple(Value) -> 165 ?hdrt("httpd_child_spec - entry", [{accept_timeout, AcceptTimeout}, 166 {debug, Debug}]), 167 Address = proplists:get_value(bind_address, Config, any), 168 Port = proplists:get_value(port, Config, 80), 169 httpd_child_spec(Config, AcceptTimeout, Debug, Address, Port); 170 171 %% In this case the AcceptTimeout and Debug will only have default values... 172 httpd_child_spec(ConfigFile, AcceptTimeoutDef, DebugDef) -> 173 ?hdrt("httpd_child_spec - entry", [{config_file, ConfigFile}, 174 {accept_timeout_def, AcceptTimeoutDef }, 175 {debug_def, DebugDef}]), 176 case httpd_conf:load(ConfigFile) of 177 {ok, ConfigList} -> 178 ?hdrt("httpd_child_spec - loaded", [{config_list, ConfigList}]), 179 case (catch httpd_conf:validate_properties(ConfigList)) of 180 {ok, Config} -> 181 ?hdrt("httpd_child_spec - validated", [{config, Config}] ), 182 Address = proplists:get_value(bind_address, Config, any) , 183 Port = proplists:get_value(port, Config, 80), 184 AcceptTimeout = 185 proplists:get_value(accept_timeout, Config, 186 AcceptTimeoutDef), 187 Debug = 188 proplists:get_value(debug, Config, DebugDef), 189 httpd_child_spec([{file, ConfigFile} | Config], 190 AcceptTimeout, Debug, Address, Port); 191 Error -> 192 Error 193 end; 194 Error -> 195 Error 196 end. 197 198 httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port) -> 199 Fd = proplists:get_value(fd, Config, undefined), 200 case Port == 0 orelse Fd =/= undefined of 201 true -> 202 httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port ); 203 false -> 204 httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Po rt) 205 end.
启动erlang/OTP里面的Web服务器(application INETS启动过程代码分析)
标签:
原文地址:http://www.cnblogs.com/andypeker/p/4662874.html