博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ranch 源码分析(三)
阅读量:4331 次
发布时间:2019-06-06

本文共 6780 字,大约阅读时间需要 22 分钟。

接上

上次讲到了ranch_conns_sup和ranch_acceptors_sup这2个ranch的核心模块,我们接着分析

首先查看ranch_conns_sup.erl

-module(ranch_conns_sup).%% API.-export([start_link/6]).-export([start_protocol/2]).-export([active_connections/1]).%...... 省略若干行%% API.-spec start_link(ranch:ref(), conn_type(), shutdown(), module(),    timeout(), module()) -> {ok, pid()}.start_link(Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol) ->    proc_lib:start_link(?MODULE, init,        [self(), Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol]).%...... 省略若干行%% Supervisor internals.-spec init(pid(), ranch:ref(), conn_type(), shutdown(),    module(), timeout(), module()) -> no_return().init(Parent, Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol) ->    process_flag(trap_exit, true),    ok = ranch_server:set_connections_sup(Ref, self()),    MaxConns = ranch_server:get_max_connections(Ref),    Opts = ranch_server:get_protocol_options(Ref),    ok = proc_lib:init_ack(Parent, {ok, self()}),    loop(#state{parent=Parent, ref=Ref, conn_type=ConnType,        shutdown=Shutdown, transport=Transport, protocol=Protocol,        opts=Opts, ack_timeout=AckTimeout, max_conns=MaxConns}, 0, 0, []).loop(State=#state{parent=Parent, ref=Ref, conn_type=ConnType,        transport=Transport, protocol=Protocol, opts=Opts,        max_conns=MaxConns}, CurConns, NbChildren, Sleepers) ->    receive        {
?MODULE, start_protocol, To, Socket} -> try Protocol:start_link(Ref, Socket, Transport, Opts) of {ok, Pid} -> shoot(State, CurConns, NbChildren, Sleepers, To, Socket, Pid, Pid); {ok, SupPid, ProtocolPid} when ConnType =:= supervisor -> shoot(State, CurConns, NbChildren, Sleepers, To, Socket, SupPid, ProtocolPid);%...... 省略若干行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.%...... 省略若干行

可以看到ranch_conns_sup不是一个典型的gen_tcp模块,

start_link/6启动init后直接使用了loop来循环,

init/7函数主要是获取了一些参数,

loop后等待消息(我们主要看start_protocol消息),loop函数根据start_protocol消息启动Protocol:start_link/4(用户编写的应用模块,这里表示echo_protocol),后面注意谁发这个消息给它

启动正常后,记录下ProtocolPid

 

继续查看ranch_acceptors_sup.erl

-module(ranch_acceptors_sup).-behaviour(supervisor).-export([start_link/4]).-export([init/1]).-spec start_link(ranch:ref(), non_neg_integer(), module(), any())    -> {ok, pid()}.start_link(Ref, NbAcceptors, Transport, TransOpts) ->    supervisor:start_link(?MODULE, [Ref, NbAcceptors, Transport, TransOpts]).init([Ref, NbAcceptors, Transport, TransOpts]) ->    ConnsSup = ranch_server:get_connections_sup(Ref),    LSocket = case proplists:get_value(socket, TransOpts) of        undefined ->            TransOpts2 = proplists:delete(ack_timeout,                proplists:delete(connection_type,                proplists:delete(max_connections,                proplists:delete(shutdown,                proplists:delete(socket, TransOpts))))),            case Transport:listen(TransOpts2) of                {ok, Socket} -> Socket;                {error, Reason} -> listen_error(Ref, Transport, TransOpts2, Reason)            end;        Socket ->            Socket    end,    {ok, Addr} = Transport:sockname(LSocket),    ranch_server:set_addr(Ref, Addr),    Procs = [        {
{acceptor, self(), N}, {ranch_acceptor, start_link, [ LSocket, Transport, ConnsSup ]}, permanent, brutal_kill, worker, []} || N <- lists:seq(1, NbAcceptors)], {ok, {
{one_for_one, 1, 5}, Procs}}.-spec listen_error(any(), module(), any(), atom()) -> no_return().listen_error(Ref, Transport, TransOpts2, Reason) -> error_logger:error_msg( "Failed to start Ranch listener ~p in ~p:listen(~p) for reason ~p (~s)~n", [Ref, Transport, TransOpts2, Reason, inet:format_error(Reason)]), exit({listen_error, Ref, Reason}).

 

这里进行最主要的操作有

打开端口Transport:listen/1开始监听端口

启动NbAcceptors个ranch_accetor:start_link进程等待连接,

 

接下来就是查看ranch_acceptor.erl

 

-module(ranch_acceptor).-export([start_link/3]).-export([loop/3]).-spec start_link(inet:socket(), module(), pid())    -> {ok, pid()}.start_link(LSocket, Transport, ConnsSup) ->    Pid = spawn_link(?MODULE, loop, [LSocket, Transport, ConnsSup]),    {ok, Pid}.-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,    flush(),    ?MODULE:loop(LSocket, Transport, ConnsSup).flush() ->    receive Msg ->        error_logger:error_msg(            "Ranch acceptor received unexpected message: ~p~n",            [Msg]),        flush()    after 0 ->        ok    end.

 

当客户端端连接,accept返回ok,ranch_conns_sup:start_protocol/2发送{?MODULE, start_protocol, self(), Socket}给ConnsSup,

 

-module(ranch_conns_sup).%% API.-export([start_link/6]).-export([start_protocol/2]).-export([active_connections/1]).%%.......省略若干行-spec start_protocol(pid(), inet:socket()) -> ok.start_protocol(SupPid, Socket) ->    SupPid ! {?MODULE, start_protocol, self(), Socket},    receive SupPid -> ok end.%%.......省略若干行

 

启动Protocol:start_link/4的详细过程,参考上面的ranch_conns_sup分析

好,这个时候基本ranch的大致结构就分析出来了,还有一些其他的细节留以后慢慢添加。

 

转载于:https://www.cnblogs.com/tudou008/p/5473985.html

你可能感兴趣的文章
su 与 su - 区别
查看>>
C语言编程-9_4 字符统计
查看>>
在webconfig中写好连接后,在程序中如何调用?
查看>>
限制用户不能删除SharePoint列表中的条目(项目)
查看>>
【Linux网络编程】使用GDB调试程序
查看>>
feign调用spring clound eureka 注册中心服务
查看>>
ZT:Linux上安装JDK,最准确
查看>>
LimeJS指南3
查看>>
关于C++ const成员的一些细节
查看>>
《代码大全》学习摘要(五)软件构建中的设计(下)
查看>>
C#检测驱动是否安装的问题
查看>>
web-4. 装饰页面的图像
查看>>
微信测试账户
查看>>
Android ListView上拉获取下一页
查看>>
算法练习题
查看>>
学习使用Django一 安装虚拟环境
查看>>
Hibernate视频学习笔记(8)Lazy策略
查看>>
CSS3 结构性伪类选择器(1)
查看>>
IOS 杂笔-14(被人遗忘的owner)
查看>>
自动测试用工具
查看>>