I want to manage HTTP or RTSP sessions with Erlang.
For example, a standart session for RTSP protocol looks like:
OPTIONS rtsp://192.168.1.55/test/ RTSP/1.0\r\n
CSeq: 1\r\n
User-Agent: VLC media player (LIVE555 Streaming Media v2008.07.24)\r\n
...
PLAY rtsp://192.168.1.55/test/ RTSP/1.0\r\n
CSeq: 5\r\n
Session: 1\r\n
Range: npt=0.000-\r\n
User-Agent: VLC media player (LIVE555 Streaming Media v2008.07.24)\r\n
The length of the every message is different.
For erlang, gen_server:listen
uses an option {active, true}
(to allow getting of an unlimited qantity of data) or {active, false}
(for getting fixed length of data).
Is there a recommended method how to get and parse such messages with variable length?
For HTTP, use one of the HTTP packet modes documented for the inet:setopts/2
function. For example, to set a socket to receive HTTP messages as binaries, you can set the {packet, http_bin}
on the socket. Have a look at my simple web server example to see how to use the HTTP packet modes.
For RTSP, there's no built-in packet parser, but because RTSP headers are line-oriented like HTTP, you can do your own header parsing using the {packet, line}
mode. In that mode, you'll receive one header at a time until you receive an empty line indicating the end of the headers. You can then change the socket to {packet, raw}
mode to receive any message body. The Content-Length
header if present indicates the size of any message body.
The {active, true}
vs {active, false}
socket modes you mention control how data arrive at the controlling process (owner) of the socket.
{active, true}
mode sends all data from the socket to the controlling process as soon as they arrive. In this mode, data arrive as messages on the owner's message queue. Receiving messages on the process message queue is great because it allows the process to also handle other non-socket-related Erlang messages while handling socket data, but {active, true}
isn't used that often because it provides no TCP back-pressure to the sender, and so a fast sender can overrun the receiver.{active, false}
mode requires the receiver to call gen_tcp:recv/2,3
on the socket to retrieve data. This doesn't have the back-pressure problem of {active, true}
but it can make message handling awkward since the Erlang process has to actively request the socket data rather than just sitting in a receive
loop as it can with the other active
modes.active
modes you didn't mention are {active, once}
and {active, N}
. In {active, once}
mode, the receiving process gets a single message via its message queue at a time, with the socket moving to the passive {active, false}
mode after each message. To get another message, the receiver has to set {active, once}
on the socket again when it's ready for the next message. This mode is nice because messages arrive on the process message queue same as they do with {active, true}
mode, but back-pressure still works. The {active, N}
mode is similar except that N
messages, rather than just one, are received before the socket reverts to passive mode.