aboutsummaryrefslogtreecommitdiffstats
path: root/doc/src/guide/transports.asciidoc
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2015-08-22 13:15:08 +0200
committerLoïc Hoguin <[email protected]>2015-08-22 13:15:08 +0200
commitf4c6da56d4fe9494f4fe23c48b8d7c3c1e9e6b42 (patch)
tree5f73255bbd51d46fccf371ff7cdd67c6bea8e7b7 /doc/src/guide/transports.asciidoc
parentd30408b2e8c14c0e56ce997f5aff0010c03cef0b (diff)
downloadranch-f4c6da56d4fe9494f4fe23c48b8d7c3c1e9e6b42.tar.gz
ranch-f4c6da56d4fe9494f4fe23c48b8d7c3c1e9e6b42.tar.bz2
ranch-f4c6da56d4fe9494f4fe23c48b8d7c3c1e9e6b42.zip
Convert the documentation to Asciidoc
Diffstat (limited to 'doc/src/guide/transports.asciidoc')
-rw-r--r--doc/src/guide/transports.asciidoc169
1 files changed, 169 insertions, 0 deletions
diff --git a/doc/src/guide/transports.asciidoc b/doc/src/guide/transports.asciidoc
new file mode 100644
index 0000000..9195376
--- /dev/null
+++ b/doc/src/guide/transports.asciidoc
@@ -0,0 +1,169 @@
+== Transports
+
+A transport defines the interface to interact with a socket.
+
+Transports can be used for connecting, listening and accepting
+connections, but also for receiving and sending data. Both
+passive and active mode are supported, although all sockets
+are initialized as passive.
+
+=== TCP transport
+
+The TCP transport is a thin wrapper around `gen_tcp`.
+
+=== SSL transport
+
+The SSL transport is a thin wrapper around `ssl`. It requires
+the `crypto`, `asn1`, `public_key` and `ssl` applications
+to be started. When starting an SSL listener, Ranch will attempt
+to automatically start them. It will not try to stop them when
+the listener is removed, however.
+
+.Starting the SSL application
+
+[source,erlang]
+ssl:start().
+
+In a proper OTP setting, you will need to make your application
+depend on the `crypto`, `public_key` and `ssl` applications.
+They will be started automatically when starting your release.
+
+The SSL transport `accept/2` function performs both transport
+and SSL accepts. Errors occurring during the SSL accept phase
+are returned as `{error, {ssl_accept, atom()}}` to differentiate
+on which socket the problem occurred.
+
+=== Sending and receiving data
+
+This section assumes that `Transport` is a valid transport handler
+(like `ranch_tcp` or `ranch_ssl`) and `Socket` is a connected
+socket obtained through the listener.
+
+You can send data to a socket by calling the `Transport:send/2`
+function. The data can be given as `iodata()`, which is defined as
+`binary() | iolist()`. All the following calls will work:
+
+.Sending data to the socket
+
+[source,erlang]
+----
+Transport:send(Socket, <<"Ranch is cool!">>).
+Transport:send(Socket, "Ranch is cool!").
+Transport:send(Socket, ["Ranch", ["is", "cool!"]]).
+Transport:send(Socket, ["Ranch", [<<"is">>, "cool!"]]).
+----
+
+You can receive data either in passive or in active mode. Passive mode
+means that you will perform a blocking `Transport:recv/3` call, while
+active mode means that you will receive the data as a message.
+
+By default, all data will be received as binary. It is possible to
+receive data as strings, although this is not recommended as binaries
+are a more efficient construct, especially for binary protocols.
+
+Receiving data using passive mode requires a single function call. The
+first argument is the socket, and the third argument is a timeout duration
+before the call returns with `{error, timeout}`.
+
+The second argument is the amount of data in bytes that we want to receive.
+The function will wait for data until it has received exactly this amount.
+If you are not expecting a precise size, you can specify 0 which will make
+this call return as soon as data was read, regardless of its size.
+
+.Receiving data from the socket in passive mode
+
+[source,erlang]
+{ok, Data} = Transport:recv(Socket, 0, 5000).
+
+Active mode requires you to inform the socket that you want to receive
+data as a message and to write the code to actually receive it.
+
+There are two kinds of active modes: `{active, once}` and
+`{active, true}`. The first will send a single message before going
+back to passive mode; the second will send messages indefinitely.
+We recommend not using the `{active, true}` mode as it could quickly
+flood your process mailbox. It's better to keep the data in the socket
+and read it only when required.
+
+Three different messages can be received:
+
+* `{OK, Socket, Data}`
+* `{Closed, Socket}`
+* `{Error, Socket, Reason}`
+
+The value of `OK`, `Closed` and `Error` can be different
+depending on the transport being used. To be able to properly match
+on them you must first call the `Transport:messages/0` function.
+
+.Retrieving the transport's active message identifiers
+
+[source,erlang]
+{OK, Closed, Error} = Transport:messages().
+
+To start receiving messages you will need to call the `Transport:setopts/2`
+function, and do so every time you want to receive data.
+
+.Receiving messages from the socket in active mode
+
+[source,erlang]
+----
+{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 happened: ~p~n", [Reason])
+end.
+----
+
+You can easily integrate active sockets with existing Erlang code as all
+you really need is just a few more clauses when receiving messages.
+
+=== Sending files
+
+As in the previous section it is assumed `Transport` is a valid transport
+handler and `Socket` is a connected socket obtained through the listener.
+
+To send a whole file, with name `Filename`, over a socket:
+
+.Sending a file by filename
+
+[source,erlang]
+{ok, SentBytes} = Transport:sendfile(Socket, Filename).
+
+Or part of a file, with `Offset` greater than or equal to 0, `Bytes` number of
+bytes and chunks of size `ChunkSize`:
+
+.Sending part of a file by filename in chunks
+
+[source,erlang]
+Opts = [{chunk_size, ChunkSize}],
+{ok, SentBytes} = Transport:sendfile(Socket, Filename, Offset, Bytes, Opts).
+
+To improve efficiency when sending multiple parts of the same file it is also
+possible to use a file descriptor opened in raw mode:
+
+.Sending a file opened in raw mode
+
+[source,erlang]
+{ok, RawFile} = file:open(Filename, [raw, read, binary]),
+{ok, SentBytes} = Transport:sendfile(Socket, RawFile, Offset, Bytes, Opts).
+
+=== Writing a transport handler
+
+A transport handler is a module implementing the `ranch_transport` behavior.
+It defines a certain number of callbacks that must be written in order to
+allow transparent usage of the transport handler.
+
+The behavior doesn't define the socket options available when opening a
+socket. These do not need to be common to all transports as it's easy enough
+to write different initialization functions for the different transports that
+will be used. With one exception though. The `setopts/2` function *must*
+implement the `{active, once}` and the `{active, true}` options.
+
+If the transport handler doesn't have a native implementation of `sendfile/5` a
+fallback is available, `ranch_transport:sendfile/6`. The extra first argument
+is the transport's module. See `ranch_ssl` for an example.