The User Datagram Protocol (UDP) serves as one of the core communication protocols in the TCP/IP suite. According to recent surveys, UDP traffic comprises over 14% of total IPv4 traffic and over 28.5% of IPv6 traffic globally on the Internet. Its performance and efficiency make it especially well-suited for time-sensitive applications ranging from VoIP to online gaming and IoT.
As a full stack developer working in IoT and multimedia streaming services, having deep knowledge of UDP packet transmission at the Linux networking layer has helped me immensely in building robust products. When performance issues or packet loss occurs in UDP-based apps, the ability to construct raw packets and test connectivity at a low level is invaluable.
In this comprehensive guide, we will master sending and receiving UDP traffic from the Linux command line using various tools.
UDP Protocol Refresher
Before going hands-on with example code, let us briefly recap how the UDP protocol functions:
-
UDP sits at the transport layer of the OSI and TCP/IP model. It allows applications on different hosts to communicate directly just like TCP.
-
However, unlike TCP, it does not establish a connection-oriented session or perform full transmission control and reliability.
-
This makes UDP extremely fast and lightweight. Packets can just be fired off to IP addresses and ports without acknowledgments or flow control.
-
UDP also utilizes checksums for basic data integrity checking – but corrupted and lost packets are simply dropped. Ensuring guaranteed delivery must be implemented at higher levels by the application.
-
All these factors make UDP suitable for performance-sensitive apps where some data loss is acceptable, like:
- Streaming audio/video
- Online gaming
- VoIP/video conferencing
- DNS lookups
- Stock data feeds
-
TCP is still better suited for use cases requiring 100% reliable transmission, such as web browsing or file transfers.
With the basics covered, let us explore practical examples of generating UDP traffic from Linux terminals.
Using Netcat for UDP Client-Server Communication
Netcat (or just nc) is one of the most flexible networking utilities under Linux and UNIX-like systems. It can open TCP connections as well as send and receive UDP packets.
Let‘s see how to establish a simple UDP client-server pipeline with netcat:
Server (192.168.1.150) Client (192.168.1.200)
netcat -ul 5005 netcat -u 192.168.1.150 5005
| \ UDP Packets / |
echo "Hello" --> <-- "Hello"
\ /
echo "World!" -->
Note the -u flag for UDP mode on both ends. The server listens for packets with -l while the client connects to the server‘s IP and specified listening port.
On the server terminal:
$ nc -ul 5005
Listening on [0.0.0.0] (family 0, port 5005)
On the client terminal:
$ nc -u 192.168.1.150 5005
Hello
World!
Any standard input on the client is sent as a UDP packet to the server, which echoes it back so we can view it locally. Terminals remain open allowing two-way communication until ended with CTRL+C.
This demonstrates UDP‘s simplicity – we instantly get a bidirectional pipeline without handshaking. Packets may sporadically get dropped without notice, but many applications are fine with occasional data loss.
Behind the scenes, netcat handles:
- Constructing valid UDP headers
- Transmitting datagrams to specified network addresses/ports
- Reassembling received datagrams
- Printing the decoded payload
This allows quick testing without writing complex application code just for transport.
Capturing and Decoding UDP Packets with tcpdump
While netcat provides a simple interface for basic connectivity testing over UDP, we want to peek at the packet-level information exchanged between the client and server.
This is where utilities like tcpdump prove invaluable for network troubleshooting and forensics. Let‘s capture some packets between our netcat client and server:
1. Start packet capture on the server:
tcpdump -nn -i eth0 udp port 5005 -w /tmp/nc-udp.pcap
This captures UDP traffic on port 5005 to a PCAP file for inspection. The -nn flag prevents host DNS resolution.
2. Generate test traffic from the client:
I used the following one-line bash command to send 5 UDP packets containing an incrementing sequence number for tracking:
for i in {1..5}; do echo "Test $i" | nc -u 192.168.1.150 5005; done
3. Inspect captured traffic in Wireshark:
Opening our PCAP file in Wireshark reveals:

We can expand each packet to view the UDP payload along with IP and Ethernet framing:

Source and destination IP addresses match our client and server machines. We also spot our transmitted message in the Data payload – Wireshark automatically detects common protocols and decoding the ASCII text.
This allows in-depth inspection of traffic flowing between hosts and pinpoint any packet loss or errors. Such visibility proves invaluable when debugging UDP-based distributed systems and streaming applications.
Additional Methods for Sending UDP Datagrams
Although netcat offers a great way to quickly get UDP connectivity, other tools provide additional capabilities:
1. socat
The socat utility has been dubbed the "swiss-army knife" tool for socket transmission, multiplexing, and redirecting. It has advanced TCP, UDP, UNIX domain sockets and other features.
Sending UDP messages with socat looks similar to netcat:
$ echo "Hello" | socat - UDP4-DATAGRAM:192.168.1.150:5005,sockbufsize=100000
The large (100KB) socket buffer configured via the sockbufsize parameter helps prevent packet loss for high-volume UDP traffic.
2. Packets from Bash with /dev/udp
On Linux, we can directly write UDP packet contents to a special device file without any utilities:
$ echo -ne "Test bash UDP" > /dev/udp/192.168.1.150/5005
This constructs a properly framed UDP datagram containing our message and queues it to the kernel networking stack for delivery.
Using the /dev/udp socket comes in handy for quick tests right from the shell with precision control.
3. Crafting Packets Programmatically
For specialized applications demanding extreme performance, tailoring UDP packet transmission using programming languages affords the highest level of control.
As an example, here is sample Golang code to send a UDP message to port 5005 of a machine at 192.168.1.150:
package main
import (
"net"
"fmt"
)
func main() {
// Resolve UDP address
udpAddr, err := net.ResolveUDPAddr("udp", "192.168.1.150:5005")
checkError(err)
// Construct message
msg := []byte("Hello Go UDP")
fmt.Printf("Sending %s\n", string(msg))
// Open socket
conn, err := net.DialUDP("udp", nil, udpAddr)
checkError(err)
// Send message
_, err = conn.Write(msg)
checkError(err)
conn.Close()
}
func checkError(err error) {
if err != nil {
panic(err)
}
}
The Go standard library provides excellent support for crafting UDP datagrams via sockets. Other languages like Rust have similar capabilities.
While more complex than just using netcat, direct socket access allows custom performance tuning and modifications to UDP packet contents. For example, certain packet telemetry fields could get updated before transmission.
This finessed control is necessary to wring out every last drop of speed in latency-sensitive financial trading systems.
Summary
The User Datagram Protocol powers a significant portion of Internet transfers thanks to its shear speed and efficiency. In this post, we explored various methods for constructing and transmitting UDP packets from the Linux CLI:
-
Netcat remains one of the easiest ways for setting up real-time, bi-directional UDP socket communication. It has been a trusty tool in my kit for years when building prototypes and testing distributed systems.
-
tcpdump enables inspection of UDP traffic for diagnosing connectivity issues or security anomalies. I rely on it when encountering packet loss or debugging production services.
-
Alternate tools like socat add advanced capabilities for controlling socket buffers and transmission at a low level.
-
The Linux /dev/udp interface delivers a simple method for precisely crafting packets straight from Bash.
-
For extreme optimization, I demonstrated how to directly manipulate the sockets interface through programming languages like Go. This unlocks the highest performance potential.
With traffic exceeding 1 Zettabyte annually, UDP will continue seeing widespread deployment in emerging technologies from Metaverse to 6G mobile networks. I hope this guide to efficiently wielding UDP from the Linux command line helps you build the next generation of blazing fast, resilient distributed applications!


