大家好,今天周六,繼續接著上一篇,跟大家分享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繼續往下看。
最后,謝謝大家的支持,晚安。