In an iPhone app, I create a CFSocket object from an existing native UDP socket and set up a data callback whenever the socket receives some data. I then add that to my main program loop:
//Set socket descriptor field
cbData.s = udpSocket.getSocketDescriptor();
CFSocketContext udpSocketContext;
memset(&udpSocketContext, 0, sizeof(udpSocketContext));
udpSocketContext.info = &cbData;
cbData.socketRef = CFSocketCreateWithNative(NULL, cbData.s, kCFSocketDataCallBack, &getSocketDataCallBack, &udpSocketContext);
cbData.runLoopSourceRef = CFSocketCreateRunLoopSource( NULL, cbData.socketRef, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), cbData.runLoopSourceRef, kCFRunLoopCommonModes);
I send 1024-byte datagrams over WiFi from a separate Mac server app every 5 mS, and receive them on my iPhone in my getSocketDataCallBack routine.
I expect getSocketDataCallBack to be called every 5 mS (to match the period of the datagrams being sent from the Mac), which happens the majority of times. BUT, the calls often get delayed by 10s or 100s of mS. Thereafter, I get a rapid sequence of callbacks (fractions of a mS) to retrieve the multiple datagrams that have piled up over that delay.
As iOS obviously keeps the delayed datagrams around,
is there any way to grab all the delayed datagrams from the system at once instead of getSocketDataCallBack being called over and over in quick succession?
[I do query how many bytes are available in the callback ala:
CFDataRef dataRef = (CFDataRef)data; numBytesReceived = CFDataGetLength(dataRef);but 'numBytesReceived' is always reported as 1024.]
- Alternatively, is there any way to improve/lessen the socket callback timing variability through other means?
I'm using socket call back for Inter Process Communication (actually, inter thread communication) with UNIX socket. How we use socket is identical to the TCP/UDP.
The code below is written in c/obj-c and using posix thread. To translate it to Swift/NSThread should not be difficult.
Note the program below works as a server side, which means the program creates socket where the clients connect to. Once the client connected to the socket, the system automatically accepts the connection and allocates another file descriptor to read/write. The socket call back reflects this two stage operation. Initially we create the socket, we then add as run-loop source so the system can call the call back when the client attempted to connect. The system accepts, then allocates and tells the call back a file descriptor to read/write with the client. We then create another run-loop source from the read/write fd and add to run-loop. This second call back is called when rx/tx data is ready.
MAIN THREAD:
The main thread creates UNIX socket and worker thread. The socket fd is passed as argument of the worker thread.
WORKER THREAD:
The program works as a server. So, it waits to get connected by client (via connect()). Once it's connected, the system automatically calls accept() and allocates read/write fd to communicate with the client. This fd is passed to accept-call back routine socketDataCallback(). Then we create another call back clientDataCallback() with the read/write fd.
If you are working at client side, things get a bit easier. You get a read/write fd with connect() call. Then you create CFSockeRef and add to run-loop by using the fd.
Hope this helps.
EDIT: How to wait with POSIX select(). To wait with POSIX select() at worker thread is simpler than socket call back. If you are on client side, then:
Run the code above at your worker thread.