Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erlang accept incoming tcp connections dynamically

What I am trying to solve: have an Erlang TCP server that listens on a specific port (the code should reside in some kind of external facing interface/API) and each incoming connection should be handled by a gen_server (that is even the gen_tcp:accept should be coded inside the gen_server), but I don't actually want to initially spawn a predefined number of processes that accepts an incoming connection). Is that somehow possible ?

like image 553
hyperboreean Avatar asked Mar 26 '11 23:03

hyperboreean


1 Answers

Basic Procedure

You should have one static process (implemented as a gen_server or a custom process) that performs the following procedure:

  1. Listens for incoming connections using gen_tcp:accept/1
  2. Every time it returns a connection, tell a supervisor to spawn of a worker process (e.g. another gen_server process)
  3. Get the pid for this process
  4. Call gen_tcp:controlling_process/2 with the newly returned socket and that pid
  5. Send the socket to that process

Note: You must do it in that order, otherwise the new process might use the socket before ownership has been handed over. If this is not done, the old process might get messages related to the socket when the new process has already taken over, resulting in dropped or mishandled packets.

The listening process should only have one responsibility, and that is spawning of workers for new connections. This process will block when calling gen_tcp:accept/1, which is fine because the started workers will handle ongoing connections concurrently. Blocking on accept ensure the quickest response time when new connections are initiated. If the process needs to do other things in-between, gen_tcp:accept/2 could be used with other actions interleaved between timeouts.

Scaling

  • You can have multiple processes waiting with gen_tcp:accept/1 on a single listening socket, further increasing concurrency and minimizing accept latency.

  • Another optimization would be to pre-start some socket workers to further minimize latency after accepting the new socket.

  • Third and final, would be to make your processes more lightweight by implementing the OTP design principles in your own custom processes using proc_lib (more info). However, this you should only do if you benchmark and come to the conclusion that it is the gen_server behavior that slows you down.

like image 149
Adam Lindberg Avatar answered Oct 07 '22 00:10

Adam Lindberg