传输
传输(Transports) 定义了和套接字交互的接口
Ranch 的传输层抽象了两个协议处理模块出来, 一个是用于普通的TCP传输层套接字 ranch_tcp
, 另一个是SSL加密传输层套接字处理模块 ranch_ssl
传输可用于连接(connecting
), 监听(listenig
), 以及接受(accepting
)连接, 也可以接收(receiving
)和发送(sending
)数据.
支持主动(active
)和被动(passive
)模式
TCP 传输
TCP 传输是一个 gen_tcp
的轻量级封装.
SSL 传输
SSL 传输是一个 ssl
的轻量级封装. 它依赖于 Erlang 提供的 crypto
,asn1
,public_key
和ssl
应用程序, 因此必须在 Ranch 之前启动. 当启动一个 SSL 监听器的时候, Ranch 会自动的启动他们. 监听器删除的时候, 不会停止他们,
启动 SSL 应用
ssl:start().
在一个正确的 OTP 设置中, 你需要保证你的应用程序依赖 crypto
, public_key
和 ssl
应用程序. 当启动你的 release 时, 他们会被自动启动.
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
模块.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。