0
votes

My understanding of UDP was that while there is a limitation of MTU size, if a datagram exceeds the MTU, it will get fragmented on the IP layer, transmitted as separate packets, and then reconstructed on the receiving end. If one of the fragments gets dropped, the UDP layer will drop the whole datagram. If everything arrives, the IP layer re-constructs the datagram and UDP should receive it as a whole.

This isn't however the behaviour I am experiencing. Here's a simple server loop

var udp = new UdpClient(port);

while (true) {
    IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);

    byte[] payload = udp.Receive(ref remote);

    Console.WriteLine($"Received {payload.Length}, IP: {remote}");
}

and sending 2999 bytes of data via netcat as following

head -c 2999 /dev/urandom | nc -4u -w1 localhost 8999

the server loop receives three times with payloads of size 1024, 1024 and 951 bytes. Since 2*1024 + 951 = 2999, it seems obvious that the data that I intended to send was actually sent, but the UdpClient is receiving it as three different datagrams.

This seems inconsistent with the fact that the UDP layers works on datagrams as a whole. Should one implement their own fragment reconstruction logic when working directly with UDP? Or is there a way to only receive complete datagrams?

1
I am not an expert, but by default DontFragment is true, try to set it to false when receiving. But if taking sockets as example, I'd expect you are responsible for combine data as Receive method will (as it seems) simply block until either data are received or buffer is full, see this question for some hints.Sinatr
Fragmentation is by routers on IP packets at layer-3. TCP and UDP don't fragment. For example,TCP segments, and that is completely different than IP fragmentation.Ron Maupin

1 Answers

1
votes

Your understanding of UDP is indeed correct. The protocol will handle fragmentation and reassembly for you transparently as long as all the fragments arrive at the destination. I had initially thought that head was potentially passing your data to netcat in 1024 byte chunks but this is not the case.

It's actually the opposite scenario: on your system netcat is reading from stdin in blocks of 1024 bytes and generating a new UDP packet each time. It seems netcat is best used for processing continuous streams of data that are mostly indifferent to how they are packetized by lower layers.

More information is available at this StackOverflow question.