When dealing with unresponsive network connections, TCP employs several timeout mechanisms at different layers:
- SYN timeout: Waiting for SYN-ACK response
- Connection establishment timeout: Full handshake completion
- Keepalive timeout: Detecting dead connections
- Retransmission timeout (RTO): Packet loss detection
On both Linux and MacOS, you can inspect current TCP timeout configurations through sysctl:
# Linux:
sysctl net.ipv4.tcp_keepalive_time net.ipv4.tcp_keepalive_intvl net.ipv4.tcp_keepalive_probes
# MacOS:
sysctl net.inet.tcp.keepalive net.inet.tcp.keepinit net.inet.tcp.keepidle
Parameter | Linux | MacOS | Description |
---|---|---|---|
Initial connection timeout | tcp_syn_retries | net.inet.tcp.keepinit | Timeout for initial SYN packet |
Keepalive idle time | tcp_keepalive_time | net.inet.tcp.keepidle | Idle time before sending keepalive probes |
Keepalive interval | tcp_keepalive_intvl | net.inet.tcp.keepintvl | Time between keepalive probes |
To temporarily modify these values (root required):
# Linux example:
sudo sysctl -w net.ipv4.tcp_keepalive_time=600
sudo sysctl -w net.ipv4.tcp_keepalive_intvl=60
sudo sysctl -w net.ipv4.tcp_keepalive_probes=5
# MacOS example:
sudo sysctl -w net.inet.tcp.keepidle=30000
sudo sysctl -w net.inet.tcp.keepintvl=30000
For application-level control in Python:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 3)
Additional diagnostic commands:
# View TCP connection states
netstat -anp tcp
# Monitor TCP retransmissions
tcpdump -i any 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'
# Check kernel TCP statistics
cat /proc/net/netstat | grep -i tcp
To make changes persistent across reboots:
# Linux: Add to /etc/sysctl.conf
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
# MacOS: Create /etc/sysctl.conf
net.inet.tcp.keepidle=30000
net.inet.tcp.keepintvl=30000
TCP timeout behavior is governed by several mechanisms that work together to detect unresponsive connections. The key parameters include:
- TCP Keepalive: Probes idle connections to detect failures
- Retransmission Timeout (RTO): Determines how long to wait before resending unacknowledged packets
- Connection Establishment Timeout: Controls SYN retransmission behavior
On both Linux and macOS, you can inspect current timeout values through sysctl:
# Linux/macOS common commands
sysctl net.ipv4.tcp_keepalive_time
sysctl net.ipv4.tcp_keepalive_intvl
sysctl net.ipv4.tcp_keepalive_probes
# Additional Linux-specific timeouts
sysctl net.ipv4.tcp_syn_retries
sysctl net.ipv4.tcp_retries2
Sample output on macOS might show:
net.ipv4.tcp_keepalive_time: 7200
net.ipv4.tcp_keepalive_intvl: 75
net.ipv4.tcp_keepalive_probes: 9
Here's how to test TCP timeout behavior programmatically:
import socket
import time
def test_connection_timeout(host, port, timeout=10):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
try:
start = time.time()
s.connect((host, port))
elapsed = time.time() - start
print(f"Connected in {elapsed:.2f} seconds")
except socket.timeout:
print(f"Connection timed out after {timeout} seconds")
finally:
s.close()
# Test against unresponsive host
test_connection_timeout("192.0.2.1", 80) # TEST-NET-1 address
To modify timeout settings without persistence (resets after reboot):
# Reduce keepalive time to 5 minutes (300 seconds)
sudo sysctl -w net.ipv4.tcp_keepalive_time=300
# Increase SYN retry attempts
sudo sysctl -w net.ipv4.tcp_syn_retries=6
For Linux (Ubuntu/Debian):
# Edit /etc/sysctl.conf
echo "net.ipv4.tcp_keepalive_time = 300" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
For macOS:
# Create / edit /etc/sysctl.conf
sudo touch /etc/sysctl.conf
echo "net.inet.tcp.keepidle=300000" | sudo tee -a /etc/sysctl.conf
For deeper analysis, consider these tools:
# TCP connection monitoring
tcpdump -i any tcp port 80 -vv
# Socket statistics
ss -o state established '( sport = :80 )'
# macOS network diagnostics
netstat -p tcp -W
Here are typical timeout situations and their solutions:
- Connection hangs indefinitely: Check tcp_retries2 (default 15 retries)
- Slow connection establishment: Reduce tcp_syn_retries from default 6
- Premature disconnection: Increase tcp_keepalive_probes from default 9