Persistent UDP Listener with Netcat: Handling Multiple Packets Without Connection Refusal


2 views

When running a simple UDP listener with:

nc -l -u -p 1234

You'll notice it terminates after receiving the first packet. Subsequent sends result in "Connection refused" errors. This happens because:

  • Netcat's default UDP mode isn't truly connectionless - it tries to maintain pseudo-connections
  • The original implementation closes the socket after first receive

Method 1: Using GNU Netcat's -k flag

nc -l -u -p 1234 -k

The -k (keep-open) flag works in GNU netcat variants to maintain the listening socket.

Method 2: Ncat (Modern alternative)

ncat -l -u -p 1234 --keep-open

Method 3: Continuous Loop (POSIX shell)

while true; do 
  nc -l -u -p 1234
done

For proper UDP service implementation, consider these robust approaches:

# Using socat for persistent UDP service
socat UDP-RECV:1234,fork -

Or with timestamp logging:

socat -u UDP-RECV:1234,fork \
  EXEC:'date +%s; cat'
  • Add proper error handling and logging
  • Consider packet size limitations (use -s or buffer controls)
  • For high traffic, implement rate limiting
  • Use timeouts (-w flag) where appropriate

Verify with continuous sending:

for i in {1..10}; do 
  echo "Packet $i" | nc -u localhost 1234
  sleep 1
done

When running a simple UDP listener with netcat:

nc -l -u -p 1234

You'll notice it only processes the first incoming packet before terminating. Subsequent packets result in "Connection refused" errors:

$ echo "test1" | nc -u localhost 1234  # Works
$ echo "test2" | nc -u localhost 1234  # Fails with "read(net): Connection refused"

Netcat's default UDP implementation treats each packet as a complete transaction. Unlike TCP, UDP is connectionless, so the traditional netcat implementation doesn't maintain state between packets.

Here are three reliable approaches to handle multiple UDP packets:

1. Using Netcat in a Loop

The simplest cross-platform solution:

while true; do 
    nc -l -u -p 1234
done

2. Using Socat (Superior Alternative)

Socat provides better UDP handling:

socat UDP-RECV:1234 -

For verbose output with timestamps:

socat -v UDP-RECV:1234 -

3. Python Persistent UDP Server

For more control, use this Python script (save as udp_server.py):

import socket

UDP_IP = "0.0.0.0"
UDP_PORT = 1234

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024)
    print(f"Received: {data.decode()} from {addr}")

Run with: python3 udp_server.py

Send test packets with netcat:

for i in {1..5}; do echo "Packet $i" | nc -u localhost 1234; done

Or with Python:

import socket

UDP_IP = "127.0.0.1"
UDP_PORT = 1234

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

for i in range(5):
    sock.sendto(f"Python packet {i}".encode(), (UDP_IP, UDP_PORT))

For continuous data streams (like logs), modify the Python server:

import socket
from datetime import datetime

UDP_IP = "0.0.0.0"
UDP_PORT = 1234

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

print(f"UDP server started at {datetime.now()}")
try:
    while True:
        data, addr = sock.recvfrom(65535)  # Max UDP packet size
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
        print(f"[{timestamp}] {addr[0]}:{addr[1]} - {data.decode()}")
except KeyboardInterrupt:
    print("\nServer terminated")
finally:
    sock.close()