Context: We are using NWConnection for UDP and TCP Connections, and wanted to know the best way to keep the number of pending send completions in control to limit resource usage
Questions:
- Is there a way to control the send rate, such that too many 'send pending completion' does not get queued. Say if I do a ‘extremely dense flurry of 10 million NWConnection.send’ will all go asynchronous without any complications? Or I would be informed once it reaches some threshold.
- Or no? And is it the responsibility of the application using NWConnection.send to limit the outstanding completion , as if they were beyond a certain limit, it would have an impact on outstanding and subsequent requests?
- If so – how would one know ‘what is supposed to be the limit’ at runtime? Is this a process level or system level limit.
- Will errors like EAGAIN and ETIMEOUT ever will be reported. In the test I simulated, where the TCP Server was made to not do receive, causing the 'socket send buffer' to become full on the sender side. On the sender side my send stopped getting complete, and became pending. Millions of sends were pending for long duration, hence wanted to know if we will ever get EAGAIN or ETIMEOUT.
Within Network framework, every connection has a send buffer [1]. That buffer has a high-water mark, that is, its expected maximum size. When you send data on the connection, the system always adds the data to the buffer. After that, one of two things happens:
-
If the amount of buffered data is below the high-water mark, the system immediately calls the completion handler associated with the send.
-
If not, it defers calling your completion handler. That is, it holds to on the completion handler and only calls it once the amount of buffered data has dropped to a reasonable level.
If you have a lot of data to send, the easiest approach is to send a chunk of data and, in the completion handler, send the next chunk. Assuming the network is consuming data slower than you’re producing it, the amount of buffered data will rapidly increase until it exceeds the high-water mark. At that point the system will stop calling your completion handler, which means you’ll stop sending new data. This gives the network tranport a big buffer of data, allowing it to optimise its behaviour on the wire.
I think the above will let you resolve all your specific questions, but please do reply here if you need further help.
Finally, if you combine Network framework with another API that uses completion handlers, you might find the techniques shown in Handling Flow Copying to be useful.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] You can think of this like a socket send buffer and a user-space buffer, but keep in mind that in many cases Network framework doesn’t use BSD Sockets for its networking but instead relies on a user-space networking stack.