В эрланге для выставления опций сокета есть функция inet:setopts(Sock, Opts). Одной из её опций является {active, Mode}.
Я хочу немного подетальнее разобрать как ей пользоваться, потому что в документации не очень хорошо это разобрано.

Режим {active, false}

Если выставить {active, false} то драйвер сокета будет накапливать приходящие данные в своём буфере и ваш процесс их не получит
либо до принудительного блокирующего вызова gen_tcp:recv(Sock, Len), либо до смены режима сокета.

Этот режим нужен прежде всего что бы лишние сообщения не попали в mailbox процесса, которому они не нужны. Например, акцептор
слушает сокет и при подключении клиента крайне нежелательно, что бы данные попали к нему, а не в отстреленный обработчик этого клиента.

Режим {active, true}

В этом режиме все приходящие данные будут немедленно отправлены в парсер пакетов и тот по необходимости пошлет
пакеты данных слушающему процессу. Пункт про парсер очень важен, потому что это ещё одна очень классная особенность эрланга: встроенные парсеры
в сокете.

inet:setopts(Sock, [{packet, 4}]) включит режим в котором первые 4 байта будут интерпретироваться как длина пакета
и процесс не получит данные, пока не будет считан весь такой пакет. Очень удобно, когда надо по сети писать законченные пакеты и снять с себя
головную боль по плавному их вычитыванию и отслеживанию длины.

Другая удобная вещь — встроенный http парсер inet:setopts(Sock, [{packet, http}]). Он распознаёт:

1. начало HTTP запроса и шлёт сообщение {http, Socket, {http_request, Method, Path, Version}};
1. заголовки и шлёт {http, Socket, {http_header, _, Name, _, Value}};
1. конец заголовков {http, Socket, http_eoh}.

Важно: после прихода http_request-а, переключается в режим httph (HTTP Headers), а после прихода http_eoh, он возвращается в режим http.

Если пришли данные, которые пакетизатору непонятны, он формирует сообщение http_error.

Теперь давайте рассмотрим ситуацию с POST запросом и его обработкой в режиме {active, true}.
В драйвер пришли сразу данные с заголовком и телом запроса. Следуя выставленному режиму он их сразу отправляет в HTTP пакетизатор,
причём именно что все-все. Включая тело запроса. После разбора http_eoh пакетизатор будет ожидать начала следующего
заголовка, а ему потечёт POST body. В результат mailbox процесса забьётся сообщениями http_error, содержащими неизвестное количество данных.
Следующий запрос отправится туда же, потому что пакетизатор магией не занимается и не сможет найти конец тела запроса.

Необходимо отметить, что избежать этой ситуации с режимом {active, true} невозможно, потому что драйвер и пакетизатор будут работать асинхронно.
Именно для подобных ситуаций и придуман режим {active, once}

Режим {active, once}

В этом режиме пакетизатор заберет из буфера драйвера ровно столько данных, сколько ему надо на отсылку одного сообщения. Соответственно, после получения http_eoh,
самое время сменить режим пакетизации на raw: inet:setopts(Sock, [{packet, raw}]), считать запрос исходя из переданного Content-Length и потом вернуться в режим http.

Sidebar