Persistent Socat Connections: Preventing EOF Termination for TCP Socket Servers


4 views

When running socat as a TCP server with fork mode, many developers encounter premature termination when the client disconnects. The core issue manifests in the logs as:

socat[4746] N socket 1 (fd 4) is at EOF
socat[4746] N exiting with status 0

This behavior occurs because socat's default behavior is to terminate when it detects EOF on the socket connection, even in fork mode. The 3-second delay you're experiencing is the time needed to restart the socat listener.

Here are three proven approaches to maintain socat availability:

# Solution 1: Keep the file descriptor open
socat -v -d -d tcp-listen:2600,reuseaddr,fork,keepalive \
      exec:"/usr/bin/cec-client",nofork

# Solution 2: Use systemd or supervisor for automatic restart
[Unit]
Description=Persistent Socat Service
After=network.target

[Service]
ExecStart=/usr/bin/socat -v -d -d tcp-listen:2600,reuseaddr,fork \
         exec:"/usr/bin/cec-client"
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

# Solution 3: Advanced bash wrapper
#!/bin/bash
while true; do
    socat -v -d -d tcp-listen:2600,reuseaddr,fork \
          exec:"/usr/bin/cec-client"
    sleep 1
done

The keepalive option enables TCP keepalive packets, while nofork prevents child process termination. For production environments, I recommend combining both the systemd approach and TCP keepalive:

socat -v -d -d tcp-listen:2600,reuseaddr,fork,keepalive,keepidle=60,keepintvl=60,keepcnt=5 \
      exec:"/usr/bin/cec-client $CEC_CLIENT_ARGS",pty,stderr

The keepidle, keepintvl, and keepcnt parameters provide fine-grained control over TCP keepalive behavior, helping maintain connections through network interruptions.

To verify your solution works:

# Test connection persistence
for i in {1..10}; do 
    echo "Test $i" | nc localhost 2600
    sleep 0.5
done

# Check process lifetime
watch -n 1 'ps aux | grep "[c]ec-client"'

You should see a single persistent socat process handling all connections without the 3-second restart delay.


When running socat with fork mode for TCP services, many developers encounter premature termination when the client disconnects. The core issue manifests like this:

socat -v -s -d -d tcp-listen:2600,reuseaddr,fork exec:"/usr/bin/cec-client $CEC_CLIENT_ARGS"

The logs show unwanted EOF detection:

2023/11/15 14:22:33 socat[8831] N socket 1 (fd 4) is at EOF
2023/11/15 14:22:34 socat[8831] N exiting with status 0

Common approaches like ignoreeof or timeout adjustments often don't work because:

  • The EOF signal comes from the underlying file descriptor
  • Forked processes inherit socket states
  • TCP connection teardown triggers automatic cleanup

This combination addresses multiple failure points:

socat -d -d \
  TCP-LISTEN:2600,reuseaddr,fork,keepalive,keepidle=10,keepintvl=10,keepcnt=2 \
  EXEC:"/usr/bin/cec-client",pty,stderr,nofork

Key improvements:

  • keepalive parameters maintain TCP connection tracking
  • pty creates persistent pseudo-terminal
  • nofork prevents file descriptor inheritance issues

For production deployments, consider socket activation:

# socat.socket
[Unit]
Description=Socat Persistent Socket

[Socket]
ListenStream=2600
Accept=yes

[Install]
WantedBy=sockets.target

# socat@.service
[Unit]
Description=Socat Instance

[Service]
ExecStart=/usr/bin/socat -d -d FD:0 EXEC:"/usr/bin/cec-client"
StandardInput=socket
StandardError=syslog

Essential verification commands:

# Check socket states
ss -tulnp | grep 2600

# Verify process persistence
watch -n 1 'ps aux | grep "[c]ec-client"'

# TCP dump analysis
tcpdump -i any port 2600 -vvv