4.2.6. ranch [1]¶
文档 [2]
Listeners¶
handlers:
ranch_tcp: 对gen_tcp简单封装
ranch_ssl: 对ssl简单封装
启动:
ok = application:start(ranch).
{ok, _} = ranch:start_listener(tcp_echo,
ranch_tcp, [
{port, 5555}, % port=0,时使用随机端口>1024
{max_connections, 100}, % 最大连接数,默认1024,可用infinity
{num_acceptors, 42} % 默认为10
],
echo_protocol, []
).
操作:
ranch:stop_listener(tcp_echo).
ranch:suspend_listener(tcp_echo).
ranch:resume_listener(tcp_echo).
% 查看
ranch:get_status(tcp_echo)
Default transport options:
binary
{active, false}, {packet, raw}, {reuseaddr, true}
% 可用以下命令覆盖
Transport:setopts/2
{backlog, 1024} and {nodelay, true}
Limiting the number of concurrent connections:
% 说明: max_connections是软限制,因backlog
% 到达max_connections时, 停止接收accepting connections
% 实践中,最大可达: max_connections + the number of acceptors
% 有些长连接会一直占connection
% 但可能交互小,而占资源少的可通过下面方法减少个数
ranch:remove_connection(Ref).
ranch:set_max_connections(tcp_echo, MaxConns).
其他:
% Upgrading
ranch:set_protocol_options(tcp_echo, NewOpts).
Opts = ranch:get_protocol_options(tcp_echo).
% Changing transport options:
ranch:set_transport_options(tcp_echo, NewOpts).
Opts = ranch:get_transport_options(tcp_echo).
% 信息查看
ranch:info().
ranch:procs(tcp_echo, acceptors).
ranch:procs(tcp_echo, connections).
Transports¶
Sending and receiving data:
Transport:send(Socket, <<"Ranch is cool!">>).
Transport:send(Socket, "Ranch is cool!").
Transport:send(Socket, ["Ranch", ["is", "cool!"]]).
Transport:send(Socket, ["Ranch", [<<"is">>, "cool!"]]).
{ok, Data} = Transport:recv(Socket, 0, 5000).
Three different messages:
1.{OK, Socket, Data}
2.{Closed, Socket}
3.{Error, Socket, Reason}
{OK, Closed, Error} = Transport:messages().
实例:
{OK, Closed, Error} = Transport:messages(),
Transport:setopts(Socket, [{active, once}]), % {active, true} | {active, true}
receive
{OK, Socket, Data} ->
io:format("data received: ~p~n", [Data]);
{Closed, Socket} ->
io:format("socket got closed!~n");
{Error, Socket, Reason} ->
io:format("error happened: ~p~n", [Reason])
end.
Sending files:
{ok, SentBytes} = Transport:sendfile(Socket, Filename).
Opts = [{chunk_size, ChunkSize}],
{ok, SentBytes} = Transport:sendfile(Socket, Filename, Offset, Bytes, Opts).
{ok, RawFile} = file:open(Filename, [raw, read, binary]),
{ok, SentBytes} = Transport:sendfile(Socket, RawFile, Offset, Bytes, Opts).
Upgrading a TCP socket to SSL:
{ok, NewSocket} = ranch_ssl:handshake(Socket, SslOpts, 5000).
Protocols¶
Writing a protocol handler:
-module(echo_protocol).
-behaviour(ranch_protocol).
-export([start_link/4]).
-export([init/3]).
start_link(Ref, _Socket, Transport, Opts) ->
Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]),
{ok, Pid}.
init(Ref, Transport, _Opts = []) ->
{ok, Socket} = ranch:handshake(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.
Using gen_statem:
-module(my_protocol).
-behaviour(gen_statem).
-behaviour(ranch_protocol).
-export([start_link/4]).
-export([init/1]).
%% Exports of other gen_statem callbacks here.
start_link(Ref, _Socket, Transport, Opts) ->
{ok, proc_lib:spawn_link(?MODULE, init, [{Ref, Transport, Opts}])}.
init({Ref, Transport, _Opts = []}) ->
%% Perform any required state initialization here.
{ok, Socket} = ranch:handshake(Ref),
ok = Transport:setopts(Socket, [{active, once}]),
gen_statem:enter_loop(?MODULE, [], state_name, {state_data, Socket, Transport}).
Embedded mode¶
init([]) ->
RanchSupSpec = {ranch_sup, {ranch_sup, start_link, []},
permanent, 5000, supervisor, [ranch_sup]},
ListenerSpec = ranch:child_spec(echo, 100,
ranch_tcp, [{port, 5555}],
echo_protocol, []
),
{ok, {{one_for_one, 10, 10}, [RanchSupSpec, ListenerSpec]}}.