ranch 源码分析(完)

时间:2021-10-18 07:11:03

接上 ranch 源码分析(三)

在上一次,根据ranch源码把大概流程理了一遍,下面我们将一些细节解释一下。

 

ranch只是一个服务的框架,它提供了传输层协议代码(ranch_tcp 和ranch_ssl),

大概可以看看这2个的源码,其实就是gen_tcp和gen_ssl的封装。

 

它做的工作可以分成

  1、根据port配置开启一个端口的linsten,(具体见ranch_acceptors_sup.erl代码)

  2、然后开启N个(根据设置)进程accpet等待client的连接, (具体见ranch_acceptors_sup.erl和ranch_acceptor.erl源码)

  3、当client连接,启动一个用户定义的应用protocol ,记录pid,(具体见ranch_conns_sup.erl源码)

  4、并把步骤2连接的socket的管理者改为步骤3的pid,剩下的就是应用模块去处理client的请求了,没ranch什么事情了(具体见下)

 

首先在ranch_acceptor.erl中有如下代码

 

-module(ranch_acceptor).

-export([start_link/3]).
-export([loop/3]).

%.......省略若干行

-spec loop(inet:socket(), module(), pid()) -> no_return().loop(LSocket, Transport, ConnsSup) ->
_
= case Transport:accept(LSocket, infinity) of
{ok, CSocket}
->
case Transport:controlling_process(CSocket, ConnsSup) of
ok
->
%% This call will not return until process has been started
%% AND we are below the maximum number of connections.
ranch_conns_sup:start_protocol(ConnsSup, CSocket);
{error, _}
->
Transport:close(CSocket)
end;
%% Reduce the accept rate if we run out of file descriptors.
%% We can't accept anymore anyway, so we might as well wait
%% a little for the situation to resolve itself.
{error, emfile} ->
receive after 100 -> ok end;
%% We want to crash if the listening socket got closed.
{error, Reason} when Reason =/= closed ->
ok
end,

%.......省略若干行

标记的地方能看到首先client连接成功的时候,会把scoket的所有者设置为Connsup 的pid

 

然后在ranch_conns_sup.erl里面

 

-module(ranch_conns_sup).

%% API.
-export([start_link/6]).
-export([start_protocol/2]).
-export([active_connections/1]).


%.......省略若干行

shoot(State=#state{ref=Ref, transport=Transport, ack_timeout=AckTimeout, max_conns=MaxConns}, CurConns, NbChildren, Sleepers, To, Socket, SupPid, ProtocolPid) ->
case Transport:controlling_process(Socket, ProtocolPid) of
ok
->
ProtocolPid
! {shoot, Ref, Transport, Socket, AckTimeout},
put(SupPid,
true),
CurConns2
= CurConns + 1,
if CurConns2 < MaxConns ->
To
! self(),
loop(State, CurConns2, NbChildren
+ 1, Sleepers);
true ->
loop(State, CurConns2, NbChildren
+ 1, [To|Sleepers])
end;
{error, _}
->
Transport:close(Socket),
%% Only kill the supervised pid, because the connection's pid,
%% when different, is supposed to be sitting under it and linked.
exit(SupPid, kill),
loop(State, CurConns, NbChildren, Sleepers)
end.

%.......省略若干行

 

如上在Connsup中,会把scoket的所有者设置成Protocol启动处理业务的Pid~~~

 

然后就没有然后呢,其实ranch只是一个框架,具体的应用实现还是要靠用户去编写,

不过好在我们有优秀的例子,比如cowboy的新版(V1.0.4版本以上)就是ranch的最好的例子之一。

 

ranch的介绍到这里就结束了,读者有疑问的请到下面提出。