123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- == Listeners
- A listener is a set of processes whose role is to listen on a port
- for new connections. It manages a pool of acceptor processes, each
- of them indefinitely accepting connections. When it does, it starts
- a new process executing the protocol handler code. All the socket
- programming is abstracted through the use of transport handlers.
- The listener takes care of supervising all the acceptor and connection
- processes, allowing developers to focus on building their application.
- === Starting a listener
- Ranch does nothing by default. It is up to the application developer
- to request that Ranch listens for connections.
- A listener can be started and stopped at will.
- When starting a listener, a number of different settings are required:
- * A name to identify it locally and be able to interact with it.
- * A transport handler and its associated options.
- * A protocol handler and its associated options.
- Ranch includes both TCP and SSL transport handlers, respectively
- `ranch_tcp` and `ranch_ssl`.
- A listener can be started by calling the `ranch:start_listener/5`
- function. Before doing so however, you must ensure that the `ranch`
- application is started.
- .Starting the Ranch application
- [source,erlang]
- ok = application:start(ranch).
- You are then ready to start a listener. Let's call it `tcp_echo`. It will
- have a pool of 100 acceptors, use a TCP transport and forward connections
- to the `echo_protocol` handler.
- .Starting a listener for TCP connections on port 5555
- [source,erlang]
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{socket_opts => [{port, 5555}]},
- echo_protocol, []
- ).
- You can try this out by compiling and running the `tcp_echo` example in the
- examples directory. To do so, open a shell in the 'examples/tcp_echo/'
- directory and run the following command:
- .Building and starting a Ranch example
- [source,bash]
- $ make run
- You can then connect to it using telnet and see the echo server reply
- everything you send to it. Then when you're done testing, you can use
- the `Ctrl+]` key to escape to the telnet command line and type
- `quit` to exit.
- .Connecting to the example listener with telnet
- [source,bash]
- ----
- $ telnet localhost 5555
- Trying 127.0.0.1...
- Connected to localhost.
- Escape character is '^]'.
- Hello!
- Hello!
- It works!
- It works!
- ^]
- telnet> quit
- Connection closed.
- ----
- === Stopping a listener
- All you need to stop a Ranch listener is to call the
- `ranch:stop_listener/1` function with the listener's name
- as argument. In the previous section we started the listener
- named `tcp_echo`. We can now stop it.
- .Stopping a listener
- [source,erlang]
- ranch:stop_listener(tcp_echo).
- === Suspending and resuming a listener
- Listeners can be suspended and resumed by calling
- `ranch:suspend_listener/1` and `ranch:resume_listener/1`,
- respectively, with the name of the listener as argument.
- Suspending a listener will cause it to stop listening and not accept
- new connections, but existing connection processes will not be stopped.
- .Suspending a listener
- [source,erlang]
- ranch:suspend_listener(tcp_echo).
- Resuming a listener will cause it to start listening and accept new
- connections again.
- It is worth mentioning, however, that if the listener is configured
- to listen on a random port, it will listen on a different port than
- before it was suspended.
- .Resuming a listener
- [source,erlang]
- ranch:resume_listener(tcp_echo).
- Whether a listener is currently running or suspended can be queried
- by calling `ranch:get_status/1` with the listener name as argument.
- === Default transport options
- By default the socket will be set to return `binary` data, with the
- options `{active, false}`, `{packet, raw}`, `{reuseaddr, true}` set.
- These values can't be overridden when starting the listener, but
- they can be overridden using `Transport:setopts/2` in the protocol.
- It will also set `{backlog, 1024}` and `{nodelay, true}`, which
- can be overridden at listener startup.
- === Listening on a random port
- You do not have to specify a specific port to listen on. If you give
- the port number 0, or if you omit the port number entirely, Ranch will
- start listening on a random port.
- You can retrieve this port number by calling `ranch:get_port/1`. The
- argument is the name of the listener you gave in `ranch:start_listener/5`.
- .Starting a listener for TCP connections on a random port
- [source,erlang]
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{socket_opts => [{port, 0}]},
- echo_protocol, []
- ).
- Port = ranch:get_port(tcp_echo).
- === Listening on privileged ports
- Some systems limit access to ports below 1024 for security reasons.
- This can easily be identified by an `{error, eacces}` error when trying
- to open a listening socket on such a port.
- The methods for listening on privileged ports vary between systems,
- please refer to your system's documentation for more information.
- We recommend the use of port rewriting for systems with a single server,
- and load balancing for systems with multiple servers. Documenting these
- solutions is however out of the scope of this guide.
- === Listening on a UNIX Domain socket
- On UNIX systems, it is also possible to use Ranch to listen on a UNIX
- domain socket by specifying `{local, SocketFile}` for the `ip` socket
- option. In this case, the port must be set to 0 or omitted. The given
- file must not exist: Ranch must be able to create it.
- .Starting a listener for TCP connections on a UNIX Domain socket
- [source,erlang]
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{socket_opts => [
- {ip, {local, "/tmp/ranch_echo.sock"}},
- {port, 0}
- ]}, echo_protocol, []
- ).
- === Performing additional setup steps on a listening socket
- If it is necessary to perform additional setup steps on the listening
- socket, it is possible to specify a function with the transport option
- `post_listen_callback`. This function will be called after the listening
- socket has been created but before accepting connections on it,
- with the socket as the single argument.
- The function must return either the atom `ok`, after which the listener
- will start accepting connections on the socket, or a tuple
- `{error, Reason}` which will cause the listener to fail starting with
- `Reason`.
- .Setting permissions on a UNIX Domain socket file
- [source,erlang]
- ----
- PostListenCb = fun (Sock) ->
- case ranch_tcp:sockname(Sock) of
- {ok, {local, SockFile}} ->
- file:change_mode(SockFile, 8#777);
- {ok, _} ->
- ok;
- Error = {error, _} ->
- Error
- end
- end,
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{
- socket_opts => [
- {ip, {local, "/tmp/ranch_echo.sock"}},
- {port, 0}],
- post_listen_callback => PostListenCb},
- echo_protocol, []
- ).
- ----
- === Accepting connections on an existing socket
- If you want to accept connections on an existing socket, you can write
- a custom `ranch_transport` implementation that fetches or otherwise
- acquires a listening socket in the `listen/1` callback and returns it
- in the form of `{ok, ListenSocket}`.
- The custom `listen/1` function must ensure that the listener process
- (usually the process calling it) is also made the controlling process
- of the socket it returns. Failing to do so will result in stop/start
- and suspend/resume not working properly for that listener.
- === Limiting the number of concurrent connections
- The `max_connections` transport option allows you to limit the number
- of concurrent connections per connection supervisor (see below).
- It defaults to 1024. Its purpose is to prevent your system from being
- overloaded and ensuring all the connections are handled optimally.
- .Customizing the maximum number of concurrent connections
- [source,erlang]
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{socket_opts => [{port, 5555}], max_connections => 100},
- echo_protocol, []
- ).
- You can disable this limit by setting its value to the atom `infinity`.
- .Disabling the limit for the number of connections
- [source,erlang]
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{socket_opts => [{port, 5555}], max_connections => infinity},
- echo_protocol, []
- ).
- The maximum number of connections is a soft limit. In practice, it
- can reach `max_connections` + the number of acceptors.
- When the maximum number of connections is reached, Ranch will stop
- accepting connections. This will not result in further connections
- being rejected, as the kernel option allows queueing incoming
- connections. The size of this queue is determined by the `backlog`
- option and defaults to 1024. Ranch does not know about the number
- of connections that are in the backlog.
- You may not always want connections to be counted when checking for
- `max_connections`. For example you might have a protocol where both
- short-lived and long-lived connections are possible. If the long-lived
- connections are mostly waiting for messages, then they don't consume
- much resources and can safely be removed from the count.
- To remove the connection from the count, you must call the
- `ranch:remove_connection/1` from within the connection process,
- with the name of the listener as the only argument.
- .Removing a connection from the count of connections
- [source,erlang]
- ranch:remove_connection(Ref).
- As seen in the chapter covering protocols, this reference is received
- as the first argument of the protocol's `start_link/3` callback.
- You can modify the `max_connections` value on a running listener by
- using the `ranch:set_max_connections/2` function, with the name of the
- listener as first argument and the new value as the second.
- .Upgrading the maximum number of connections
- [source,erlang]
- ranch:set_max_connections(tcp_echo, MaxConns).
- The change will occur immediately.
- === Customizing the number of acceptor processes
- By default Ranch will use 10 acceptor processes. Their role is
- to accept connections and spawn a connection process for every
- new connection.
- This number can be tweaked to improve performance. A good
- number is typically between 10 or 100 acceptors. You must
- measure to find the best value for your application.
- .Specifying a custom number of acceptor processes
- [source,erlang]
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{socket_opts => [{port, 5555}], num_acceptors => 42},
- echo_protocol, []
- ).
- === Customizing the number of connection supervisors
- By default Ranch will use one connection supervisor for each
- acceptor process (but not vice versa). Their task is to
- supervise the connection processes started by an acceptor.
- The number of connection supervisors can be tweaked.
- Note that the association between the individual acceptors and
- connection supervisors is fixed, meaning that acceptors will
- always use the same connection supervisor to start connection
- processes.
- .Specifying a custom number of connection supervisors
- [source,erlang]
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{socket_opts => [{port, 5555}], num_conns_sups => 42},
- echo_protocol, []
- ).
- === Setting connection count alarms
- The `alarms` transport option allows you to configure alarms
- which will be triggered when the number of connections under a connection
- supervisor reaches or exceeds the defined treshold.
- The `alarms` transport option takes a map with alarm names as keys and alarm
- options as values.
- Any term is allowed as an alarm name.
- Alarm options, defining the alarm behavior, are again a map with the following
- keys:
- `type`::
- The alarm type. Currently, `num_connections` is the only allowed type.
- `treshold`::
- The alarm treshold. When the number of connections under a connection
- supervisor reaches or exceeds this value, the alarm will trigger and
- call the function given in the `callback` key.
- `callback`::
- The alarm function, that is, the function which will be called when the
- alarm is triggered. Its arguments are the listener name, the alarm
- name, the Pid of the triggering connection supervisor, and the Pids of
- all the connection processes under that supervisor.
- `cooldown` (5000)::
- The minimum time to elapse before the alarm can trigger again, in
- milliseconds.
- .Setting an alarm to log warnings when the number of connections exceed 100
- [source,erlang]
- ----
- Alarms = #{
- my_alarm => #{
- type => num_connections,
- treshold => 100,
- callback => fun(Ref, Name, ConnSup, ConnPids]) ->
- logger:warning("Warning (~s): "
- "Supervisor ~s of listener ~s "
- "has ~b connections",
- [Name, Ref, ConnSup, length(ConnPids)])
- end
- }
- },
- {ok, _} = ranch:start_listener(tcp_echo,
- ranch_tcp, #{alarms => Alarms, socket_opts => [{port, 5555}]},
- echo_protocol, []
- ).
- ----
- In the example code, an alarm named `my_alarm` is defined, which will
- call the given function when the number of connections under a
- connection supervisor reaches or exceeds 100. When the number of
- connections is still (or again) above 100 after the default cooldown
- period of 5 seconds, the alarm will trigger again.
- === When running out of file descriptors
- Operating systems have limits on the number of sockets
- which can be opened by applications. When this maximum is
- reached the listener can no longer accept new connections. The
- accept rate of the listener will be automatically reduced, and a
- warning message will be logged.
- ----
- =ERROR REPORT==== 13-Jan-2016::12:24:38 ===
- Ranch acceptor reducing accept rate: out of file descriptors
- ----
- If you notice messages like this you should increase the number
- of file-descriptors which can be opened by your application. How
- this should be done is operating-system dependent. Please consult
- the documentation of your operating system.
- === Using a supervisor for connection processes
- Ranch allows you to define the type of process that will be used
- for the connection processes. By default it expects a `worker`.
- When the `connection_type` configuration value is set to `supervisor`,
- Ranch will consider that the connection process it manages is a
- supervisor and will reflect that in its supervision tree.
- Connection processes of type `supervisor` can either handle the
- socket directly or through one of their children. In the latter
- case the start function for the connection process must return
- two pids: the pid of the supervisor you created (that will be
- supervised) and the pid of the protocol handling process (that
- will receive the socket).
- Instead of returning `{ok, ConnPid}`, simply return
- `{ok, SupPid, ConnPid}`.
- It is very important that the connection process be created
- under the supervisor process so that everything works as intended.
- If not, you will most likely experience issues when the supervised
- process is stopped.
- === Upgrading
- Ranch allows you to upgrade the protocol options. This takes effect
- immediately and for all subsequent connections.
- To upgrade the protocol options, call `ranch:set_protocol_options/2`
- with the name of the listener as first argument and the new options
- as the second.
- .Upgrading the protocol options
- [source,erlang]
- ranch:set_protocol_options(tcp_echo, NewOpts).
- All future connections will use the new options.
- You can also retrieve the current options similarly by
- calling `ranch:get_protocol_options/1`.
- .Retrieving the current protocol options
- [source,erlang]
- Opts = ranch:get_protocol_options(tcp_echo).
- === Changing transport options
- Ranch allows you to change the transport options of a listener with
- the `ranch:set_transport_options/2` function, for example to change the
- number of acceptors or to make it listen on a different port.
- .Changing the transport options
- [source,erlang]
- ranch:set_transport_options(tcp_echo, NewOpts).
- You can retrieve the current transport options by calling
- `ranch:get_transport_options/1`.
- .Retrieving the current transport options
- [source,erlang]
- Opts = ranch:get_transport_options(tcp_echo).
- === Obtaining information about listeners
- Ranch provides two functions for retrieving information about the
- listeners, for reporting and diagnostic purposes.
- The `ranch:info/0` function will return detailed information
- about all listeners.
- .Retrieving detailed information
- [source,erlang]
- ranch:info().
- The `ranch:procs/2` function will return all acceptor or listener
- processes for a given listener.
- .Get all acceptor processes
- [source,erlang]
- ranch:procs(tcp_echo, acceptors).
- .Get all connection processes
- [source,erlang]
- ranch:procs(tcp_echo, connections).
|