设为首页收藏本站

Erlang中文论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 18880|回复: 0
打印 上一主题 下一主题

ranch初窥1

[复制链接]
跳转到指定楼层
楼主
发表于 2018-7-13 17:18:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 茶叶feng 于 2018-7-13 17:23 编辑

# ranch #
- 从我的有道云笔记转过来的, 可以直接访问连接http://note.youdao.com/noteshare?id=20b0bc4806aed935da3f258816eae7da&sub=AF84BFF80C114F3898D6FC07648EEC99
## 进程关系图 ##

```
graph TB
ranch-->|开始ranch|ranch_sup
ranch_sup-->|启动监听进程|ranch_listener_sup
ranch_listener_sup---|更新监听管理进程|ranch_server
ranch_listener_sup-->|启动socket连接管理进程|ranch_conns_sup
ranch_listener_sup-->|启动接收socket管理进程|ranch_acceptor_sup
ranch_conns_sup---|更新连接相关信息|ranch_server
ranch_acceptor-->|同步启动socket消息处理进程|ranch_protocol
ranch_acceptor_sup---|更新监听端口|ranch_server
ranch_acceptor_sup-->|启动接收socket的进程|ranch_acceptor
ranch_acceptor-->|通知连接管理进程启动socket新的消息处理进程|ranch_conns_sup
```

## 整体理解 ##
从整体上的话,ranch主要是三层的监控树
* 第一层 ranch\_sup,负责整个应用的启动,启动了ranch_server进程,它管理了整个应用的配置和连接数据
* 第二层 ranch\_listener\_sup,负责连接的管理
* 第三层 ranch\_conns\_sup和ranch\_acceptors_sup,这两个分别用来处理新的连接和获得新的连接
当然最底层的ranch\_acceptor是应用中的重要角色,每当有新的连接,都会把控制权交给ranch\_conns\_sup,由它统一管理
## ranch.app #
启动模块为ranch\_app,说明需要找到ranch\_app.erl文件去启动应用  
## ranch_app.erl ##
根据参数启动测试的功能,主要启动了一个ranch\_sup监控进程
## ranch_sup.erl ##
新建一个名为ranch\_server的ets表,同时启动并监控ranch\_server进程,策略为one\_for\_one
## ranch_server.erl ##
启动了一个进程,管理ranch\_server这个ets表,提供多个接口
set\_new\_listener_opts:设置监听进程的参数
set\_connections\_sup:增加新的连接进程的监控进程Pid,并且对该进程进行monitor监视,把{MonitorRef, Pid}添加到#state.monitors中
set\_listener\_sup:增加一个监听进程的监控进程Pid,并且对该进程进行monitor监视,并且把{MonitorRef, Pid}添加到#state.monitors中
set_addr:在ets中记录地址
set\_max\_conns:设置最大连接数量
set\_trans\_opts:设置传输协议参数
set\_proto\_opts:设置协议参数
到此为止,ranch应用的准备工作已经结束,剩下的就差外部的调用了
***
## ranch.erl ##
ranch应用的调用模块,通过start\_listener/6来初始化ranch的功能模块,给它提供功能参数, **其中需要特别说明的是有一个Transport参数,是ranch的协议模块名,要么是ranch\_ssl,要么就是ranch\_tcp,Protocol参数是回调的模块,需要用户自己来实现,实现的行为模式必须是ranch\_protocol,** 先在ranch\_sup下面启动了一个ranch\_listener\_sup进程,该进程做了什么,接下来将详细介绍,至少在这里我们知道,ranch的正式使用由ranch\_listener\_sup进程启动开始。
```
-spec start_listener(ref(), module(), any(), module(), any())
        -> supervisor:startchild_ret().
start_listener(Ref, Transport, TransOpts, Protocol, ProtoOpts) ->
        NumAcceptors = proplists:get_value(num_acceptors, TransOpts, 10),
        start_listener(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts).

-spec start_listener(ref(), non_neg_integer(), module(), any(), module(), any())
        -> supervisor:startchild_ret().
start_listener(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
                when is_integer(NumAcceptors) andalso is_atom(Transport)
                andalso is_atom(Protocol) ->
        _ = code:ensure_loaded(Transport),
        case erlang:function_exported(Transport, name, 0) of
                false ->
                        {error, badarg};
                true ->
                        Res = supervisor:start_child(ranch_sup, child_spec(Ref, NumAcceptors,
                                        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,
                        maybe_started(Res)
        end.
```
```
-spec child_spec(ref(), module(), any(), module(), any())
        -> supervisor:child_spec().
child_spec(Ref, Transport, TransOpts, Protocol, ProtoOpts) ->
        NumAcceptors = proplists:get_value(num_acceptors, TransOpts, 10),
        child_spec(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts).

-spec child_spec(ref(), non_neg_integer(), module(), any(), module(), any())
        -> supervisor:child_spec().
child_spec(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
                when is_integer(NumAcceptors) andalso is_atom(Transport)
                andalso is_atom(Protocol) ->
        {{ranch_listener_sup, Ref}, {ranch_listener_sup, start_link, [
                Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts
        ]}, permanent, infinity, supervisor, [ranch_listener_sup]}.

```
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|Erldoc.com  

GMT+8, 2024-4-20 13:30 , Processed in 1.448844 second(s), 16 queries , File On.

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表