File Descriptors and Socket Backlog
File Descriptors
File descriptors (FDs) are integer handles that reference I/O resources in Unix-like systems.
- Each process has its own FD table
- Standard descriptors: 0 (stdin), 1 (stdout), 2 (stderr)
- New resources get the lowest available number
- Each FD consumes kernel memory
In Network Applications
Server Process FDs: - FD #3: Listening socket (accepting new connections) - FD #4: Connection to Client 1 - FD #5: Connection to Client 2 ...and so on
System Limits
- Per-process limit: ulimit -n (typically 1,024 by default)
- System-wide limit: /proc/sys/fs/file-max
- To check current limits:
bash
# Per-process soft limit ulimit -n # Per-process hard limit ulimit -Hn # System-wide limit (Linux) cat /proc/sys/fs/file-max # macOS sysctl kern.maxfiles
Socket Backlog
The socket backlog (controlled by somaxconn) is the maximum queue length for pending connections.
Key Characteristics
- Controls only the queue of pending connections waiting to be accepted
- Does NOT limit total established connections
- Default value is typically 128 on most systems
- Set via listen(socket, backlog) call in code
Connection Flow
- Client initiates connection (SYN packet)
- Connection enters backlog queue (SYN_RECEIVED state)
- Connection waits until application calls accept()
- Once accepted, no longer counts against backlog limit
System Settings
- Linux: /proc/sys/net/core/somaxconn
- macOS: kern.ipc.somaxconn
- To modify temporarily:
bash
# Linux sudo sysctl -w net.core.somaxconn=1024 # macOS sudo sysctl -w kern.ipc.somaxconn=1024
Practical Applications
Web Server
- 1 listening socket
- 1 FD per client connection
- High connection count, relatively short-lived
- For 10,000 concurrent users: requires 10,001 FDs
Chat Server
- 1 listening socket
- 1 FD per connected client
- Medium connection count, long-lived
- Typically low bandwidth per connection
Game Server
- 1 listening socket
- 1 FD per player
- CPU and bandwidth often become limiting factors before FD limit
- More resource-intensive per connection than chat
Performance Tuning
For Maximum Connections
bash# Increase file descriptor limit sudo bash -c 'echo "* soft nofile 65536" >> /etc/security/limits.conf' sudo bash -c 'echo "* hard nofile 65536" >> /etc/security/limits.conf' # Increase backlog size sudo sysctl -w net.core.somaxconn=4096
Socket Buffer Tuning
Different applications have different optimal buffer sizes:
- Chat: smaller buffers (4-8KB)
- Game: moderate buffers (16-32KB)
- Streaming: larger buffers (64-256KB)
Database Connection Pools
MySQL/PostgreSQL Connection Pool
- Database server creates 1 listening socket (/tmp/mysql.sock or similar)
- Each client connection creates a new FD (not new socket files)
- Application connection pool of 5 creates 5 FDs on application side and 5 FDs on DB side
- All use the same socket file as the connection point
Pool Size Recommendations
- Rule of thumb: pool_size = num_workers × threads_per_worker
- For Puma with 4 workers, 5 threads: set pool to 20
- Too small: timeout errors
- Too large: excessive resource usage
Use Cases
Handling 100+ Concurrent Requests with 5 Threads
- First 5 requests process immediately
- Remaining requests enter queue
- Maximum queue size determined by socket backlog (somaxconn)
- Beyond backlog limit: connection refused
High-Traffic Scenarios
- Increase both FD limit and socket backlog
- Consider multiple worker processes
- Implement load balancing across multiple servers
- Monitor resource usage closely
Common Issues
- "Too many open files": Hit FD limit
- "Connection refused": Backlog queue full
- Slow response times: Queuing delay