• 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才慢慢走进我们的视野,下面我们慢慢分析.。。。。(未完待续)。
    
    
    
  • 相关阅读:
    [引]ASP.NET MVC 4 Content Map
    [转]ASP.NET MVC 2: Model Validation
    [转]ASP.NET MVC中你必须知道的13个扩展点
    [转]Best way to sort a DropDownList in MVC3 / Razor using helper method
    [转]Sql Server参数化查询之where in和like实现详解
    [转]Oracle Stored Procedures Hello World Examples
    [转]oracle的ANYDATA数据类型
    重构中对设计模式的反思
    poj2186 Popular Cows --- 强连通
    mac下通过xcodebuild使用oclint
  • 原文地址:https://www.cnblogs.com/tudou008/p/5466619.html
Copyright © 2020-2023  润新知