A datagram is all-or-nothing per read — too small a buffer means the tail is dropped on the floor, not saved for later.
TCP is a byte stream: a read hands you whatever bytes have arrived, and message boundaries are yours to recover. UDP is different — it preserves datagram boundaries, so one recvfrom returns exactly one datagram, no more and no less.
That guarantee has a sharp edge. If a datagram is larger than the buffer you pass, the kernel copies only as many bytes as fit and silently discards the rest of that datagram. The excess is gone — the next recvfrom returns the next datagram, never the leftover tail. On Linux, the MSG_TRUNC flag lets you learn the datagram's true length so you can at least detect that loss happened.
You hand recvfrom a buffer and its length. It copies one datagram, capped at that length, and returns how many bytes it wrote. Without help, a truncated read looks identical to one that fit exactly — both just return a count. Pass MSG_TRUNC and the return value becomes the datagram's real length, so a value larger than your buffer is the tell that bytes were dropped.
// UDP receive with truncation detection (Linux)
char buf[8]; // deliberately small buffer
ssize_t n = recvfrom(fd, buf, sizeof buf, MSG_TRUNC,
(struct sockaddr *)&src, &srclen);
if (n < 0) { perror("recvfrom"); return; }
// With MSG_TRUNC, n is the datagram's TRUE length,
// not how many bytes landed in buf.
if ((size_t)n > sizeof buf) {
// *** TRUNCATION: n - sizeof(buf) bytes were discarded ***
// buf holds only the first sizeof(buf) bytes; the tail is gone.
log_drop(n - sizeof buf);
}
// Fix: size buf to the maximum datagram you can receive.
| Property | Detail |
|---|---|
| Datagram boundary | One recvfrom returns exactly one datagram — UDP never splits or merges them |
| Truncation behaviour | Oversized datagram: first buflen bytes kept, the tail silently discarded |
| Detection | MSG_TRUNC makes the return value the real length; > buflen means loss |
| Fix | Size the buffer to the maximum datagram (up to 65507 bytes) or the path MTU payload |
recvfrom just returns a count. Without MSG_TRUNC you cannot tell a perfectly-sized read from a truncated one.recvfrom returns a different, whole datagram.MSG_TRUNC. The flag is your only signal that truncation occurred. Skip it and corrupted, half-parsed messages flow downstream unnoticed.A sensor emits a 1500-byte reading as a single UDP datagram, but the receiver loops on recvfrom with a 512-byte buffer. Each read returns 512 bytes and the kernel discards the remaining 988 bytes — silently, with no error. The reader parses a truncated payload and never notices the gap. The fix is to size the buffer to the maximum datagram (65535 is the conventional ceiling for the UDP payload), and to pass MSG_TRUNC so any future oversize is flagged rather than swallowed.
1. A 12-byte UDP datagram arrives and you recvfrom into an 8-byte buffer. What happens to bytes 8 through 11?
2. How do you reliably detect that a UDP read was truncated on Linux?
Coach note: if a pick doesn't land, give it another pass — the reasoning is what sticks.