ranch
博客专区 > hncscwc 的博客 > 博客详情
ranch
hncscwc 发表于4年前
ranch
  • 发表于 4年前
  • 阅读 49
  • 收藏 0
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

摘要: ranch整理备忘

1. 简单介绍

ranch是一个使用erlang开发的socket acceptor pool for TCP protocols.

cowboy中使用ranch作为网络通信的基础

2. 使用

(1) 启动ranch应用

application:start(ranch).

(2) 侦听接收

ranch:start_listener(Ref, NbAcceptors,
                     Transport, TransOpts,
                     Protocol, ProtoOpts).

其中

Ref:  标识该侦听的唯一标识

NbAcceptors:  acceptor进程的个数

Transport:  传输模块的名称, 通常为 ranch_tcp或ranch_ssl

TransOpts:  侦听的相关选项参数

                 默认的选项参数有 binary, {active, false}, {packet, raw}, {reuseaddr, true}

                 注意: 这几个默认的参数在调用start_listeners时不能更改, 但可以调用Transport:setopts/2进行修改

                 其他选项参数有 侦听端口:{port, Port}, 最大连接数: {max_connections, MaxConn}

Protocol:  回调协议解析模块

ProtoOpts:  回调协议解析模块的所需参数

例如

ranch:start_listener(client, 10, 
                     ranch_tcp,
                     [{port, 80}, {max_connections, infinity}],
                     cowboy_protocol, []).

(3) 协议解析模块

该模块需要实现ranch_protocol行为, 即导出start_link/4函数. 该函数会由ranch_conns_sup进行回调, 该函数返回一个进程pid——{ok, Pid}.

回调start_link/4 传入的四个参数为 侦听的唯一标识Ref, 新连接的socket句柄Sock, 传输模块名称Transport以及协议解析模块的参数(ranch:start_listener中传入的).

在协议解析模块中, 通过调用传输模块提供的 recv/3 和 send/2 接口完成数据的收发工作。

3.  内部细节

(1) 监督树

ranch应用启动会默认创建ranch_sup进程和ranch_server进程, 当调用ranch:start_listerner后, 创建ranch_listener_sup, ranch_conns_sup, ranch_acceptor_sup等进程, 关系如上图所示. 多次调用start_listerner接口时, 会有多个ranch_listener_sup进程以及它的子进程.

(2) start_listener的流程

注意两个同步流程

1) ranch_acceptor进程调用start_protocol同步等待ranch_conns_sup进程回复, 用于控制最大连接数

2) 协议解析模块需调用ranch:accept_ack/1 同步等待ranch_conns_sup回复后, 才能真正进行数据的接收。

ranch_conns_sup.erl
start_protocol(SupPid, Socket) ->
    SupPid ! {?MODULE, start_protocol, self(), Socket},
    receive
        SupPid ->
            ok
    end.


loop(...)
    receive
        {?MODULE, start_protocol, To, Socket} ->
            case Protocol:start_link(Ref, Socket, Transport, Opts) of
                {ok, Pid} -> 
                    Transport:controlling_process(Socket,Pid),
                    Pid ! {shoot, Ref},
                    put(Pid, true),
                    CurConns2 = CurConns + 1,
                    if CurCons2 < MaxConns ->
                           To ! self(),
                           loop(...);
                       true ->
                           loop(...)
                    end;
                _ ->
                    To ! self(),
                    Transport:close(Socket),
                    loop(...)
            end;
        ...

ranch.erl
accept_ack(Ref) ->
    receive
        {shoot, Ref} ->
            ok
    end.

(3)  ranch_server进程

该进程的作用是记录通过调用start_listerner侦听的相关信息, 包括

侦听端口:  ets:insert(?TAB, {{port, Ref}, Port})

最大连接数:  ets:insert(?TAB, {{max_conns, Ref}, MaxConns})

协议解析参数:  ets:insert(?TAB, {{opts, Ref}, Opts})

连接池监督者进程:  ets:insert(?TAB, {{conns_sup, Ref}, Pid})

记录这些信息的目的是为了动态进行设置.

ranch_server:set_max_connections(Ref, MaxConnections)
ranch_server:set_new_listener_opts(Ref, MaxConnections, Opts)
ranch_server:set_protocol_optsions(Ref, ProtoOpts)

通过这些接口可进行动态设置, 这几接口的实现都是向ranch_server进程投递消息, ranch_server收到消息后更新ets表中的数据, 并根据ref找到对应的连接池监督者进程, 并消息通知最新的配置信息.

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 63
博文 66
码字总数 76137
×
hncscwc
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: