1. What is inetd?
Imagine you are running a Linux server that provides many network services — echo, FTP, telnet, time, daytime, and more. The traditional approach is to run a separate server process for each service, all the time, even when no client is using them. That wastes memory and CPU.
inetd (pronounced “inet-dee”) solves this problem. It is a single daemon called the Internet Superserver. Instead of running one process per service, inetd listens on all the service ports. When a client connects to any of those ports, inetd wakes up and starts the right server program just for that connection. Once the request is handled, the server exits.
This means only one process (inetd) is always running instead of dozens, which saves a lot of system resources — especially important on older or resource-limited systems.
Traditional vs inetd Approach
❌ Traditional: Many Processes Always Running
Wastes memory — all idle most of the time!
✅ With inetd: One Process, On-Demand Servers
Saves memory — servers start only on real requests!
2. How inetd Works — Step by Step
When a client connects to a port managed by inetd, inetd follows these steps automatically. Understanding this helps you write servers that work with inetd without worrying about all the setup code yourself.
Select the Service Entry
inetd reads /etc/inetd.conf to find which server program handles this port. Each line in that file maps a port/protocol to a server program. inetd picks the right entry based on the incoming connection’s port and protocol (TCP or UDP).
fork() — Create a Child Process
inetd calls fork() to create a child process. The child will become the actual server. The parent (inetd) goes back to monitoring ports. This means inetd is never blocked waiting for one server to finish — it can accept new connections on other ports simultaneously.
inetd also sets up a handler for SIGCHLD so that when a child server finishes, it is automatically reaped (cleaned up) to avoid zombie processes.
Set Up the Child as a Daemon
The child process is automatically configured as a daemon. inetd handles all the usual daemon initialization steps — things like detaching from the terminal, setting the working directory, and more. The server programmer does not need to write any of this boilerplate code.
Redirect Socket to stdin/stdout/stderr
This is the key step that makes inetd-invoked servers so simple. inetd duplicates the socket file descriptor onto file descriptors 0, 1, and 2 — which are standard input (STDIN_FILENO), standard output (STDOUT_FILENO), and standard error.
After this, the server can just read from fd 0 to receive data from the client and write to fd 1 to send data back — exactly like reading/writing to a terminal. No need to call accept() or handle socket file descriptors directly.
All other file descriptors that are open in inetd but not needed by the server are closed.
exec() — Run the Server Program
Finally, inetd calls exec() to replace the child process with the actual server program. Since the socket is already mapped to stdin/stdout, the server can immediately start communicating with the client using simple read() and write() calls.
3. How File Descriptor Redirection Works
This is the most important trick inetd uses. Here is what happens to file descriptors before exec() runs:
Before inetd Remaps
After inetd Remaps (dup2)
read(STDIN_FILENO, buf, size), it is actually reading from the network socket connected to the client. And write(STDOUT_FILENO, buf, size) sends data back to the client. The server does not even know it is talking to a network socket!4. The /etc/inetd.conf Configuration File
inetd reads its configuration from /etc/inetd.conf. Each line in this file describes one network service. The format is:
service socket-type protocol wait/nowait user server-path server-args
Here is a real example for the echo service:
echo stream tcp nowait root /bin/is_echo_sv is_echo_sv
| Field | Value in Example | Meaning |
|---|---|---|
| service | echo | Service name from /etc/services (maps to port 7) |
| socket-type | stream | stream = TCP, dgram = UDP |
| protocol | tcp | Transport protocol: tcp or udp |
| wait/nowait | nowait | Controls whether inetd waits for the server to finish (see below) |
| user | root | User account to run the server as |
| server-path | /bin/is_echo_sv | Full path to the server executable |
| server-args | is_echo_sv | argv[0] for the server (usually same as program name) |
5. nowait vs wait — The Critical Difference
nowait (used for TCP)
After inetd forks a child to handle a client, inetd does not wait for that child to finish. It immediately goes back to monitoring the listening socket. This means inetd can accept a new client connection even while the previous client’s server is still running.
This is the right choice for TCP because each TCP connection gets a dedicated connected socket, so inetd can keep accepting new connections on the listening socket.
wait (used for UDP)
After inetd forks a child for a UDP service, inetd stops monitoring that socket and waits for the server to exit before listening again. This is needed because UDP has no concept of a separate connected socket — all datagrams arrive on the same socket, so inetd must hand full control of that socket to the server.
6. What inetd Does For You (Summary)
Without inetd, every server must do all of these steps itself. With inetd, none of this is needed:
7. inetd and System Load
inetd reduces system load in two ways:
- Fewer idle processes: Without inetd, each service runs a server process continuously even when no clients are connected. With inetd, these processes only exist when actually needed.
- Simplified programming: Since inetd handles all initialization, server programs are shorter and less likely to have bugs in the setup code.
This is especially important on embedded systems or servers with many services but low simultaneous usage — exactly the kind of scenario common in Linux-based embedded devices.
Interview Questions — Part 1
inetd (Internet superserver daemon) is a single daemon that listens on multiple network ports simultaneously. It was created to reduce the number of always-running server processes on a system. Instead of having a separate process for each service waiting for connections, inetd monitors all ports and starts the appropriate server only when a connection arrives. This saves memory and simplifies server programming.
(1) Select the matching service entry from /etc/inetd.conf. (2) Call fork() to create a child process. (3) Set up the child as a daemon. (4) Duplicate the connected socket onto file descriptors 0, 1, and 2 (stdin/stdout/stderr) and close all other file descriptors. (5) Call exec() to replace the child with the actual server program.
nowait is used for TCP services. After forking a child, inetd does not wait for that child and immediately returns to monitoring the listening socket for new connections. wait is used for UDP services. After forking a child, inetd stops monitoring that socket and waits for the server child to exit, because UDP has no per-connection socket and the server needs exclusive access to the datagram socket.
By mapping the socket to stdin (fd 0) and stdout (fd 1), the server program can communicate with the client using standard read() and write() calls. The server does not need to know about sockets at all — it just reads input and writes output. This dramatically simplifies server code and even allows non-network programs to be used as inetd servers.
A zombie process is a process that has finished but whose exit status has not yet been collected by the parent using wait(). This leaves a dead process entry in the process table. inetd prevents this by installing a SIGCHLD signal handler. When a child server exits, the kernel sends SIGCHLD to inetd, and the handler calls wait() to reap the zombie. This keeps the system clean even as many server children are created and exit.
dup2(oldfd, newfd) makes newfd refer to the same file description as oldfd, closing newfd first if it was open. inetd uses dup2() to map the connected socket (which has some fd number like 3 or 4) onto fd 0 (stdin), fd 1 (stdout), and fd 2 (stderr). After this, the server can use STDIN_FILENO and STDOUT_FILENO to communicate with the client without knowing the actual socket fd number.
