Elixir Ranch: 传输层抽象

传输

传输(Transports) 定义了和套接字交互的接口app

Ranch 的传输层抽象了两个协议处理模块出来, 一个是用于普通的TCP传输层套接字 ranch_tcp, 另外一个是SSL加密传输层套接字处理模块 ranch_sslsocket

传输可用于链接(connecting), 监听(listenig), 以及接受(accepting)链接, 也能够接收(receiving)和发送(sending)数据.tcp

支持主动(active)和被动(passive)模式函数

TCP 传输

TCP 传输是一个 gen_tcp 的轻量级封装.atom

SSL 传输

SSL 传输是一个 ssl 的轻量级封装. 它依赖于 Erlang 提供的 crypto,asn1,public_keyssl 应用程序, 所以必须在 Ranch 以前启动. 当启动一个 SSL 监听器的时候, Ranch 会自动的启动他们. 监听器删除的时候, 不会中止他们,加密

启动 SSL 应用code

ssl:start().

在一个正确的 OTP 设置中, 你须要保证你的应用程序依赖 crypto, public_keyssl应用程序. 当启动你的 release 时, 他们会被自动启动.orm

SSL 传输的 accept/2 函数同时执行传输(transport)和SSL 接受(SSL accepts)的操做. 在SSL接受阶段若是发生错误, 将返回 {error, {ssl_accept, atom()}} 以区分问题发生在哪一个套接字上.接口

发送和接收数据

能够经过 Transport:send/2 函数给套接字发送数据. 数据的类型为 iodata(), 它包含两种子类型 binary() | iolist()进程

经过套接字发送数据

Transport:send(Socket, <<"Ranch is cool!">>).
Transport:send(Socket, "Ranch is cool!").
Transport:send(Socket, ["Ranch", ["is", "cool!"]]).
Transport:send(Socket, ["Ranch", [<<"is">>, "cool!"]]).

能够经过被动模式主动模式接收数据. 被动模式执行阻塞的 Transport:recv/3 调用. 主动模式把数据做为消息接收.

默认全部数据是做为二进制接收的. 也能够把接收的数据当成字符串.

用被动模式接收数据要求一个函数调用. 第一个参数为套接字, 第三个参数为读取超时值(超时后返回{error, timeout}.

第二个参数为想要接收的数据字节数. 该函数将会等待数据, 直到它接收到了指定长度的数据. 若是不指定精确的值, 也能够指定为0 , 它会尽快的返回, 而无论数据的大小.

被动模式下,从套接字读取数据

{ok, Data} = Transport:recv(Socket, 0, 5000).

主动模式要求你告知套接字你想要把数据做为消息接收, 而且编写代码来接收消息.

主动模式有两种类型 {active, once}{active, true}, 前者发送一个消息后就当即回到被动模式. 后者无限地发送消息. 不推荐使用 {active, true} 模式, 这种模式会很快的把进程邮箱塞满. 更好的是, 把数据留在套接字中, 仅当须要的时候再读取.

能够接收三种不懂的消息

  • {OK, Socket, Data}

  • {Closed, Socket}

  • {Error, Socket, Reason}

取决于选择的传输模块, OK, Closed, 和 Error 的值有可能不一样. 要可以正确的匹配他们, 必须首先调用 Transport:messages/0函数.

获取传输的主动消息标识

{OK, Closed, Error} = Transport:messages().

要开始接收消息, 你须要调用 Transport:setopts/2 函数, 而且每次再接收消息的时候都要这样作.

主动模式下, 从套接字接收消息

{OK, Closed, Error} = Transport:messages(),
Transport:setopts(Socket, [{active, once}]),
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 happended: ~p~n", [Reason])
end.

能够很容易的把主动套接字集成到 Erlang 代码中, 当接收消息时, 仅仅须要很少的代码.

发送文件

经过套接字发送名为 Filename 的文件:

经过文件名发送文件

{OK, SentBytes} = Transport:sendfile(Socket, Filename).

若是是文件的一部分, 使用大于等于0的Offset, Bytes 字节数, 以及 ChunkSize 块大小:

发送文件的一部分块

Opts = [{chunk_size, ChunkSize}]
{ok, SentBytes} = Transport:sendfile(Socket, Filename, Offset, Bytes, Opts).

要改善发送同一个文件的多个部分, 可使用以raw模式打开的文件描述符:

发送一个以 raw 模式打开的文件

{ok, RawFile} = file:open(Filename, [raw, read, binary]),
{ok, SentBytes} = Transport:sendfile(Socket, RawFile, Offset, Bytes, Opts).

编写传输处理模块

传输处理模块是一个实现了 ranch_transport 行为的模块(好比(ranch_tcp, ranch_ssl).

ranch_tcp.erl文件头两行说明了这个事实

-module(ranch_tcp).
-behaviour(ranch_transport).

为了可以透明的使用传输处理模块, 须要行为中定义的一系列回调函数.

当打开套接字时, 该行为没有定义可用的套接字选项. 由于对于使用不一样的传输, 编写不一样的初始化函数是至关容易的, 所以不须要有共同的传输选项设置, 一个例外是, setopts/2 必须 实现 {active, once}{active, true} 选项

若是传输没有实现 sendfile/5, 将使用 ranch_transport:sendfile/6 替代. 多的第一个参数是传输模块. 例子能够参考 ranch_ssl 模块.

相关文章
相关标签/搜索