In gen_tcp active mode, how does Elixir decide how many bites a 'message' is?

Context:

https://www.erlang.org/doc/man/gen_tcp.html

gen_tcp::connect takes active: as one of the socket options.

From my limited understanding:

  • passive: we manually call recv
  • active mode: incoming tcp ‘messages’ sent to process as an erlang msg
  • active once: to avoid mailbox overload, only first msg from tcp is sent this way

Question: how does Erlang/Elixir know what a single tcp ‘message’ is? Is it just a packet?

1 Like

Disclaimer: I don’t actually know, but my understanding (based on reading the docs) is:

It depends on the PacketType specified when opening the socket. Erlang’s inet module (which underlies gen_tcp) has a support for a few different packet types. They are described here: Erlang -- inet. If the protocol you’re implementing is compatible with one if those supported by inet, each message you receive in your mailbox will all be a complete packet.

If the protocol you’re implementing is not supported by inet, you will use packet type raw. In this case, I believe the number of bytes you get will depend on the OS directly - inet will not try to package up packets for you, but just send you a message every time it receives bytes from the OS kernel. The exception being, if your socket transfers to passive mode, inet will buffer bytes until you go back to active, in which case I expect you will get all the buffered bytes at once. There is some mention in the inet docs about raw socket options you can pass to the kernel which might affect the behavior, but these are non-portable (see the Example section on the page I linked above).

I hope that made sense :slight_smile:

2 Likes

Thanks; this sounds like a reasonable interpretation of the docs. If we imagine a conversation that went:

We have a basic TCP socket here.
Let’s add builtin parser that covers 99%* of the message types.
Sure, why not.

Then we probably end up with something like the cases covered above.

[*] made up number