Apple's documentation says that:
In iOS, POSIX networking is discouraged because it does not activate the cellular radio or on-demand VPN. Thus, as a general rule, you should separate the networking code from any common data processing functionality and rewrite the networking code using higher-level APIs.
That document doesn't mention the dispatch_io
APIs from GCD, so it's not clear if they activate the radio on iOS or not. In fact, it's not clear whether the "special sauce" is in the code that opens the connection, or in the code that reads and writes on it.
What if I connect a socket using the POSIX API and pass it to dispatch_io_create
? What if I create a socket using the CFStream API, extract the file descriptor, and pass it to dispatch_io_create
? Which of those methods makes networking work properly on iOS? Both? Neither?
I've not tested it, but my guess would be that all the VPN-on-demand and Cellular-radio magic happens at initiation/setup/connection opening time, because that's really the only thing that would really make sense. Therefore, I would expect that your approach of digging out the file descriptor with CFSocketGetNative
and using dispatch_io
would work just fine, at least until one of the connections gets broken (assuming TCP/stateful connections). AFAICT recovering from broken connections is not built into CFSocket/CFNetworkStream
anyway, so it's probably six-to-one...
I've read a few vague news items about the new multi-path TCP implementation coming to iOS (sounds like link bonding revisited), and it's unclear if that's available to 3rd party apps or not, but I think of it this way: Either the multi-path support is in the protocol stack (and is therefore abstracted to the app developer as a single socket/file descriptor) and will work transparently to the 3rd party app developer on any TCP socket, or it relies on some higher-level user-land component to handle/aggregate the multiple underlying connections into one, and will force developers into a higher-level API. You already have to use the higher-level API to set up the connection if you want the VPN-on-demand and cell-radio functionality, so it would seem that it wouldn't matter to you either way.
If your goal is merely to have an asynchronous I/O session serviced by blocks, it seems like the safest course of action (given that this stuff seems kinda underspecified in the docs) would be to use the runloop based API and have the callback call a block. If you're worried about interaction between your network I/O and the main runloop, you can always spool up a background thread with its own runloop and schedule your I/O over there. From having done I/O with both APIs in the past, I would expect the runloop approach to be, performance-wise, functionally equivalent to using the dispatch_io
API in the common case (i.e. it's not noticeably slower unless you're doing something really high-throughput or really chatty.)
FWIW, this question might stand a better chance of getting an authoritative response if posted to Apple's developer support board (but it might not too.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With