ranch 源码分析(一)

时间:2021-02-10 16:49:51

以前写了一个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才慢慢走进我们的视野,下面我们慢慢分析.。。。。(未完待续)。