I understand how TCP goes about this - through various methods such as Congestion Window (CWND), Sliding Window, Slow Start and Fast Recovery - it's basically built into the protocol. I understand that when shaping or MSS clamping is applied along the path, TCP can adapt its segment size and transfer rate accordingly.
I also understand that QUIC (which runs over UDP) implements its own version of loss detection and congestion control. QUIC is sort of like a highly-tuned, low-latency, more extensible version of TCP, built for HTTP3, but it can also transport any other application data.
However it's not clear to me how applications - which do not use QUIC - can determine:
- How many UDP datagrams can be sent at once
- How large each UDP datagram can be (if PMTUD does not work due to ICMP replies being disabled/blocked by middleboxes)
It's not really clear to me how UDP, being a best effort protocol, doesn't just flood the link/path between the sender and recipient, resulting in significant packet loss.
Or put in other way: How can an application, which needs to send a high volume of data, either statically or dynamically determine the available bandwidth on the path between the sender and receiver, and adjust its datagram size and transfer rate accordingly?*
I understand that RTP has things like RTCP that allow it to limit/increase flow rates or change codecs to reduce/increase packet sizes, for quality control. When running Iperf tests using UDP, you can set the available bandwidth with the "-b" attribute. DNS and DHCP, which use UDP, have comparatively tiny datagram sizes, and will just retry until they receive a response or time out.
*The answer, based on my current understanding, would be: The application would just be designed to use TCP if it needed to send/receive a high volume of data (such as backups or high-definition streaming), and simply wouldn't use UDP unless it also had a supporting out-of-band protocol like RTCP or could be certain of the bandwidth available (i.e. set by the user, like with Iperf).