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 模塊.

相關文章
相關標籤/搜索