Ranch尝鲜

简介

ranch是一个用erlang实现的tcp链接的管理池,他有如下特点(摘抄自git库):

Ranch aims to provide everything you need to accept TCP connections with a small code base and low latency while being easy to use directly as an application or to embed into your own.
Ranch provides a modular design, letting you choose which transport and protocol are going to be used for a particular listener. Listeners accept and manage connections on one port, and include facilities to limit the number of concurrent connections. Connections are sorted into pools, each pool having a different configurable limit.
Ranch also allows you to upgrade the acceptor pool without having to close any of the currently opened sockets.

简单来说就是

  • Ranch很轻量,且内敛,集成到项目中很容易。
  • 通过使用模块化的设计,可以实现同时存在多个tcp连接池且允许他们有不同的配置,不同的处理逻辑,可以做到完全隔离。
  • 同时支持在线更新连接池的配置而不用关闭当前已经打开的socket。
    Git库地址

简单实例

项目用一个简单的echo服务介绍了一个简单的ranch使用模型。

tcp_echo_app.erl

start(_Type, _Args) ->
	{ok, _} = ranch:start_listener(tcp_echo, 1,
		ranch_tcp, [{port, 5555}], echo_protocol, []),
	tcp_echo_sup:start_link().

echo_protocol.erl

-module(echo_protocol).
-behaviour(ranch_protocol).

-export([start_link/4]).
-export([init/4]).

start_link(Ref, Socket, Transport, Opts) ->
	Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]),
	{ok, Pid}.

init(Ref, Socket, Transport, _Opts = []) ->
	ok = ranch:accept_ack(Ref),
	loop(Socket, Transport).

loop(Socket, Transport) ->
	case Transport:recv(Socket, 0, 5000) of
		{ok, Data} ->
			Transport:send(Socket, Data),
			loop(Socket, Transport);
		_ ->
			ok = Transport:close(Socket)
	end.

当然要使用这些逻辑的基础前提是首先application:ensure_all_started(ranch).

直接看的话还是有点难懂,主要体现在:

  • 为什么首先要启动一个ranch的application才能开始监听端口
  • ranch:start_listener 实现了什么逻辑,每个指定的参数内容是什么
  • echo_protocol模块的ranch_protocol是一个怎样的定义,它start_link函数的入参从何而来
  • tcp_echo_sup的作用是什么

现在我们带着这些问题开始学习ranch的逻辑

1. 为什么首先要启动一个ranch的application才能开始监听端口

要解答这个问题,我们得先知道ranch的application启动后都做了哪些事情
ranch_app.erl

-module(ranch_app).
-behaviour(application).

start(_, _) ->
	_ = consider_profiling(),
	ranch_sup:start_link().

我们暂时忽略consider_profiling(实际上这部分是用来做prof分析的根据app配置决定是否启动,和功能逻辑无关),也就是启动了ranch_sup一个貌似supervisor的管理者

ranch_sup.erl

-module(ranch_sup).
-behaviour(supervisor).

-spec start_link() -> {ok, pid()}.
start_link() ->
	supervisor:start_link({local, ?MODULE}, ?MODULE, []).

init([]) ->
	ranch_server = ets:new(ranch_server, [
		ordered_set, public, named_table]),
	Procs = [
		{ranch_server, {ranch_server, start_link, []},
			permanent, 5000, worker, [ranch_server]}
	],
	{ok, {
  {one_for_one, 10, 10}, Procs}}.

看来并没有猜错,ranch_sup就是一个supervisor,他建立了一张ets表,然后定义了自己的child的描述。再回到例子的ranch:start_listener 就可以大胆猜测下,其实就是启动一个supervisor用来管理之前特性说明里的,同时支持多个tcp端口监听实例,而这些实例统一由ranch_sup来管理,当然这还是我们的猜测,还要看下ranch_server的具体实现才能确定。

ranch_server.erl

-module(ranch_server).
-behaviour(gen_server).
-define(TAB, ?MODULE).

start_link() ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
	
init([]) ->
	Monitors = [{
  {erlang:monitor(process, Pid), Pid}, Ref} ||
		[Ref, Pid] <- ets:match(?TAB, {
  {conns_sup, '$1'}, '$2'})],
	{ok, #state{monitors=Monitors}}.

看起来并不是我们猜测的那样,r

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值