Can NWConnection.receive(minimumIncompleteLength:maximumLength:) return nil data for UDP while connection remains .ready?

I’m using Network Framework with UDP and calling:

connection.receive(minimumIncompleteLength: 1,
                   maximumLength: 1500) { data, context, isComplete, error in
    ... // Some Logic
}

Is it possible for this completion handler to be called with data==nil if I haven't received any kind of error, i.e., error==nil and the connection is still in the .ready state?

Answered by DTS Engineer in 875918022

That’s not the right API to use for receiving datagrams. Rather, use the receiveMessage(completion:) method or one of its variants. That ensures that you get the entire datagram in one hit.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

That’s not the right API to use for receiving datagrams. Rather, use the receiveMessage(completion:) method or one of its variants. That ensures that you get the entire datagram in one hit.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

We are building our own custom protocol, and we will be assembling the bytes that we are receiving. We wanted to reduce the kernel overhead of assembling bytes that receiveMessage(completion:) does. The question we have is that while using the receive api can the completion handler can be called even if data==nil?

We wanted to reduce the kernel overhead of assembling bytes that receiveMessage(completion:) does.

I have two things to note about this.

First, there’s no guarantee that your network connections are being run by the kernel. Our platforms have a user-space networking stack and Network framework will choose that over the in-kernel stack in many common cases.

Second, I’m concerned about this concept of “assembling bytes”. In general, UDP datagrams shouldn’t be fragmented and thus there’s no assembling of data at all. A packet arrives, it contains the full UDP datagram, and the content of that datagram is delivered to you.

If you’re building something that does fragment UDP datagrams — that is, it sends datagrams that are larger than the path MTU and thus are subject to IP fragmentation — then it’d be better to work on not doing that rather than trying to worry about optimising this path.

Moreover, even in that case I don’t think the partial datagram will be delivered to you. In the case of UDP, the networking stack collects together all the fragments before it can deliver any part of the datagram [1].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] In theory this isn’t a requirement, but in practice that’s how it actually works.

Can NWConnection.receive(minimumIncompleteLength:maximumLength:) return nil data for UDP while connection remains .ready?
 
 
Q