ranch 源码分析(一)
以前写了一个ranch的处理流程,http://www.cnblogs.com/tudou008/p/5197314.html ,就只有一张图,不是很清晰,现在有空做个源码分析。
ranch的源码(版本v1.2.1 下载链接https://github.com/ninenines/ranch.git)
我们从一个最简单的例子开始 tcp_echo
1 [root@erlang004 ranch-master]# pwd 2 /home/erlang/ranch-master 3 [root@erlang004 ranch-master]# ll -R examples/tcp_echo/ 4 examples/tcp_echo/: 5 total 16 6 -rw-rw-r-- 1 erlang erlang 56 Jan 20 06:15 Makefile 7 -rw-rw-r-- 1 erlang erlang 543 Jan 20 06:15 README.md 8 -rw-rw-r-- 1 erlang erlang 79 Jan 20 06:15 relx.config 9 drwxrwxr-x 2 erlang erlang 4096 May 6 09:38 src 10 11 examples/tcp_echo/src: 12 total 16 13 -rw-rw-r-- 1 erlang erlang 572 Jan 20 06:15 echo_protocol.erl 14 -rw-rw-r-- 1 erlang erlang 346 Jan 20 06:15 tcp_echo_app.erl 15 -rw-rw-r-- 1 erlang erlang 284 Jan 20 06:15 tcp_echo.app.src 16 -rw-rw-r-- 1 erlang erlang 370 Jan 20 06:15 tcp_echo_sup.erl
首先查看tcp_echo_app.erl
%% Feel free to use, reuse and abuse the code in this file. %% @private -module(tcp_echo_app). -behaviour(application). %% API. -export([start/2]). -export([stop/1]). %% API. start(_Type, _Args) -> {ok, _} = ranch:start_listener(tcp_echo, 1, ranch_tcp, [{port, 5555}], echo_protocol, []), tcp_echo_sup:start_link(). stop(_State) -> ok.
可以看到这里,启动了ranch:start_listener/6
而且后面启动了tcp_echo_sup:start_link/0,我们先看看tcp_echo_sup做了什么
tcp_echo_sup.erl
%% Feel free to use, reuse and abuse the code in this file. %% @private -module(tcp_echo_sup). -behaviour(supervisor). %% API. -export([start_link/0]). %% supervisor. -export([init/1]). %% API. -spec start_link() -> {ok, pid()}. start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). %% supervisor. init([]) -> {ok, {{one_for_one, 10, 10}, []}}.
tcp_echo_sup明显没有做任何业务,下面我们来详细查看ranch.erl
-module(ranch). -export([start_listener/6]). -export([stop_listener/1]). -export([child_spec/6]). -export([accept_ack/1]). -export([remove_connection/1]). -export([get_addr/1]). -export([get_port/1]). -export([get_max_connections/1]). -export([set_max_connections/2]). -export([get_protocol_options/1]). -export([set_protocol_options/2]). -export([filter_options/3]). -export([set_option_default/3]). -export([require/1]). %...... 省略若干行 -spec start_listener(ref(), non_neg_integer(), module(), any(), module(), any()) -> supervisor:startchild_ret(). start_listener(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) when is_integer(NbAcceptors) andalso is_atom(Transport) andalso is_atom(Protocol) -> _ = code:ensure_loaded(Transport), %% @todo Remove in Ranch 2.0 and simply require ssl. _ = ensure_ssl(Transport), case erlang:function_exported(Transport, name, 0) of false -> {error, badarg}; true -> Res = supervisor:start_child(ranch_sup, child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)), Socket = proplists:get_value(socket, TransOpts), case Res of {ok, Pid} when Socket =/= undefined -> %% Give ownership of the socket to ranch_acceptors_sup %% to make sure the socket stays open as long as the %% listener is alive. If the socket closes however there %% will be no way to recover because we don't know how %% to open it again. Children = supervisor:which_children(Pid), {_, AcceptorsSup, _, _} = lists:keyfind(ranch_acceptors_sup, 1, Children), %%% Note: the catch is here because SSL crashes when you change %%% the controlling process of a listen socket because of a bug. %%% The bug will be fixed in R16. catch Transport:controlling_process(Socket, AcceptorsSup); _ -> ok end, Res end.
%...... 省略若干行
start_listener在这里开始,
对比例子里面的参数发现,对应的值和意义如下
Ref, :tcp_echo 表示应用的标记
NbAcceptors, :1 应用启动的进程数(就是后面的ranch_acceptor的个数)
Transport, :ranch_tcp 传输层的模块(ranch_tcp或者ranch_ssl,可以用户定义)
TransOpts, :[{port, 5555}] 传输层的参数
Protocol, :echo_protocol 应用层的处理模块,一般用户根据ranch_protocol编写
ProtoOpts : [] 应用层参数定义
这时ranch才慢慢走进我们的视野,下面我们慢慢分析.。。。。(未完待续)。