ranch 源码分析(完)

接上 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的新版(V2.0.0版本以上)就是ranch的最好的例子之一。

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

时间: 2024-10-12 12:54:41

ranch 源码分析(完)的相关文章

ranch 源码分析(三)

接上ranch 源码分析(二) 上次讲到了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

ranch 源码分析(二)

接上ranch 源码分析(一) 上次讲到了ranch.erl的start_listener函数,下面我们详细分析下这个函数 -module(ranch). %...... 省略若干行 -spec start_listener(ref(), non_neg_integer(), module(), any(), module(), any()) -> supervisor:startchild_ret(). start_listener(Ref, NbAcceptors, Transport, T

ranch 源码分析(一)

以前写了一个ranch的处理流程,http://www.cnblogs.com/tudou008/p/5197314.html ,就只有一张图,不是很清晰,现在有空做个源码分析. ranch的源码(版本v1.2.1 下载链接https://github.com/ninenines/ranch.git) 我们从一个最简单的例子开始 tcp_echo 1 [[email protected] ranch-master]# pwd 2 /home/erlang/ranch-master 3 [[ema

cowboy源码分析(一)

前段时间导读了ranch的源码,具体见ranch 源码分析(一), 现在整理了下ranch框架下经典应用cowboy. 源码地方:https://github.com/ninenines/cowboy(目前使用的是cowboy-1.0.4版本) 还是找其中最简单的例子来入手,那就选这个static_world吧~~ 首先我们来看static_world_app.erl [[email protected] src]# cat static_world_app.erl %% Feel free t

HashMap与TreeMap源码分析

1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Java这么久,也写过一些小项目,也使用过TreeMap无数次,但到现在才明白它的实现原理).因此本着"不要重复造轮子"的思想,就用这篇博客来记录分析TreeMap源码的过程,也顺便瞅一瞅HashMap. 2. 继承结构 (1) 继承结构 下面是HashMap与TreeMap的继承结构: pu

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

Spark的Master和Worker集群启动的源码分析

基于spark1.3.1的源码进行分析 spark master启动源码分析 1.在start-master.sh调用master的main方法,main方法调用 def main(argStrings: Array[String]) { SignalLogger.register(log) val conf = new SparkConf val args = new MasterArguments(argStrings, conf) val (actorSystem, _, _, _) =

Solr4.8.0源码分析(22)之 SolrCloud的Recovery策略(三)

Solr4.8.0源码分析(22)之 SolrCloud的Recovery策略(三) 本文是SolrCloud的Recovery策略系列的第三篇文章,前面两篇主要介绍了Recovery的总体流程,以及PeerSync策略.本文以及后续的文章将重点介绍Replication策略.Replication策略不但可以在SolrCloud中起到leader到replica的数据同步,也可以在用多个单独的Solr来实现主从同步.本文先介绍在SolrCloud的leader到replica的数据同步,下一篇

LevelDB源码分析--Iterator

我们先来参考来至使用Iterator简化代码2-TwoLevelIterator的例子,略微修改希望能帮助更加容易立即,如果有不理解请各位看客阅读原文. 下面我们再来看一个例子,我们为一个书店写程序,书店里有许多书Book,每个书架(BookShelf)上有多本书. 类结构如下所示 class Book { private: string book_name_; }; class Shelf { private: vector<Book> books_; }; 如何遍历书架上所有的书呢?一种实