Why Does TCP/UDP Lose Packets? Deep Dive into Causes and Fixes
This article explores the root causes of packet loss in TCP and UDP—including application bugs, kernel buffer limits, network congestion, protocol limitations, and handshake failures—and presents practical solutions such as code optimization, socket tuning, congestion‑control adjustments, and forward error correction techniques.
Part1 TCP Protocol Packet Loss Reasons
Although TCP provides reliable transmission over unreliable networks, packet loss can still occur when data is missing or dropped during communication. The most common sources are problems in the sending or receiving stages.
When a server sends large amounts of data using frequent
send()calls, the
sendoperation may fail due to logic bugs, inadequate multithread synchronization, or buffer overflows. If the application does not handle these failures, the client receives less data than expected, leading to loss.
1.1 Application‑level mishandling
Logical errors, such as miscalculating the amount of data to send, cause missing data. Multithreaded programs that access shared resources without proper locks can overwrite or drop data, similar to a relay race where runners grab the baton at the same time.
Buffer overflows happen when the amount of data written to the TCP send buffer exceeds its capacity, causing excess data to be discarded—like pouring water into a full cup.
TCP sockets allocate a send buffer and a receive buffer.
When
send(msg)is called, the packet is copied into the kernel's send buffer rather than being sent directly to the NIC. The receive buffer holds incoming packets until the application reads them.
If the receive buffer becomes full, the TCP receive window shrinks to zero (a “zero‑window” condition) and the sender is instructed to stop sending; any further data will be dropped.
1.2 Poor network conditions
Network congestion, high latency, and link failures all contribute to TCP packet loss. When traffic exceeds a link’s capacity, buffers fill and excess packets are discarded. High latency triggers unnecessary retransmissions, and broken links (e.g., cut fiber) prevent packets from reaching their destination.
1.3 Limitations of TCP mechanisms
TCP’s retransmission and congestion‑control algorithms can fail under severe congestion or prolonged high latency, causing time‑outs and packet drops.
1.4 Packet loss during the three‑way handshake
The
listenbacklog limits how many half‑opened connections can be queued before
accept()is called. If the backlog is exceeded, SYN packets are dropped. The kernel code handling this looks like:
inet_listen -->>> sk->sk_max_ack_backlog = backlog;
inet_csk_listen_start--->> reqsk_queue_alloc
for (lopt->max_qlen_log = 3;
(1 << lopt->max_qlen_log) < nr_table_entries;
lopt->max_qlen_log++);During the first handshake, if the SYN queue is full, the packet is dropped:
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
#ifdef CONFIG_SYN_COOKIES
if (sysctl_tcp_syncookies) {
want_cookie = 1;
} else
#endif
goto drop;
}
...
drop:
return 0;
}When the SYN queue overflows, the kernel records the event in
/proc/net/snmp.
Part2 UDP Protocol Packet Loss Reasons
UDP drops packets mainly because the receiver cannot process incoming datagrams quickly enough, causing the kernel to discard excess packets to protect system resources.
Relevant kernel code:
__udp4_lib_rcv--->>> udp_queue_rcv_skb
if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
if (rc == -ENOMEM)
UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag);
goto drop;
}The receive buffer size limits how many packets can be queued; once full, new packets are dropped and the error counters can be seen in
/proc/net/snmp:
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
Udp: 672 0 0 670 0 02.1 Connection‑less and unreliable nature
UDP does not establish a handshake nor provide acknowledgments or retransmissions, so any network instability directly results in lost packets.
2.2 Buffer‑related issues
If the receive buffer is too small for the incoming data rate, it fills quickly and subsequent packets are discarded.
2.3 Improper sending strategies
Oversized UDP packets that exceed the MTU are fragmented; loss of any fragment causes the whole packet to be unrecoverable. Sending at excessively high rates also overwhelms the receiver’s buffer.
Part3 TCP Packet Loss Solutions
3.1 Optimize application code
Review and test application logic, fix bugs, and use proper synchronization primitives (e.g., mutexes, semaphores, condition variables) to avoid data races.
Adjust buffer sizes according to workload and release processed data promptly.
3.2 Tune TCP parameters
Increase retransmission attempts and timeout values via
/etc/sysctl.conf(e.g.,
net.ipv4.tcp_retries2=15) and select an appropriate congestion‑control algorithm (CUBIC, BBR, RENO).
# Increase retransmission attempts
sudo sysctl -w net.ipv4.tcp_retries2=15
# Increase timeout
sudo sysctl -w net.ipv4.tcp_fin_timeout=30
# View current algorithm
sysctl net.ipv4.tcp_congestion_control
# Set BBR algorithm
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr3.3 Network optimization measures
Upgrade bandwidth, apply QoS policies, and use monitoring tools (Wireshark, tcpdump) to detect congestion.
# Capture packets with tcpdump
sudo tcpdump -i eth0 -w capture.pcapPart4 UDP Packet Loss Solutions
4.1 Forward Error Correction (FEC)
FEC adds redundant data to the stream so that lost packets can be reconstructed without retransmission, at the cost of extra bandwidth and latency.
4.2 Application‑level retransmission
Implement timers, sequence numbers, and acknowledgments in the application to resend lost packets, balancing reliability against added traffic.
4.3 Optimize receiver processing
Buffer incoming packets quickly and process them in separate worker threads or asynchronously to avoid buffer overflow.
4.4 Proper socket configuration
Increase the socket receive buffer size with
setsockopt(..., SO_RCVBUF, ...)and limit packet size to the network MTU. Control sending rate based on feedback from the receiver.
# Example: set receive buffer size
int size = 4*1024*1024; // 4 MiB
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));Deepin Linux
Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.