Why do I get packet loss when using GKMatchSendDataReliable? - ios

I have a multiplayer iOS game, and I am sending data using GKMatchSendDataReliable. However, occasionally, the data packet is lost. I've checked on the sending end and I am not getting an error. I'm just not receiving it on the receiving in. It is intermittent, and I have NSLogs right at the beginning of my receive method, so I always know when I get a message.
Is GKMatchSendDataReliable 100% reliable? It seems like a waste to have to set up my own reliable data sending routines.
It seems that this only happens when one device is on Verizon's LTE network. I havn't tried any other cellular network. When using Wi-Fi only, not necessarily the same wi-fi, it works fine.

This happens to me too. It appears that while GKMatchSendDataReliable is oodles more reliable than GKMatchSendDataUnreliable (which loses about 2% of packets in my tests), GKMatchSendDataReliable seems to occassionally lose the first packet I send (immediately after connecting).

My users also complain that some data may be accidentally lost during the game. I wrote a test app and figured out that GKMatchSendDataReliable is not really reliable. On weak internet connection (e.g. EDGE) some packets are regularly lost without any error from the Game Center API.
So the only option is to add an extra transport layer for truly reliable delivery.
I wrote a simple lib for this purpose: RoUTP. It saves all sent messages until acknowledgement for each received, resends lost and buffers received messages in case of broken sequence.
In my tests combination "RoUTP + GKMatchSendDataUnreliable" works even beter than "RoUTP + GKMatchSendDataReliable" (and of course better than pure GKMatchSendDataReliable which is not really reliable).

Apple stated that this was a bug and fixed in iOS7

Related

Is it possible to implement flow control for CBCharacteristicWriteWithoutResponse?

Is it possible to use writeValue with type CBCharacteristicWriteWithoutResponse and still have some flow control to avoid sending data faster than BLE stack manages to actually send it out? Currently it works on Android but not on iOS.
The long story.
I have previously implemented duplex communication channel over BLE on Android. It is basically using two ATT characteristics - one is write/writeWithoutResponse and the other is notifiable.
On Android, even when I use writeWithoutResponse, Android sends me onCharacteristicWrite callback to signal that the data packet has at least reached BLE stack, and in this callback I send out the next data packet with size of current ATT_MTU-3 bytes.
This works fine, the data reaches the target intact and I can achieve transfer speeds about 10 KB/s.
But on iOS there is a problem. When using writeValue with type CBCharacteristicWriteWithoutResponse, iOS (at least iOS 8) does not call didWriteValueForCharacteristic and this is intended and documented behavior. Thus I have no way of knowing if the data packet has reached BLE stack. The best I can is to call writeValue in a loop. Also, writeValue seems to be non blocking (async). As the result, not all of my data reaches the peripheral device. In the logs I see that the incoming data stream is stopped too soon. My guess is that if I call writeValue too fast, iOS is just carelessly overwriting previous cached writable characteristic value and thus misses some data bytes in between.
If I use writeValue with CBCharacteristicWriteWithResponse, it works fine, and what's strange - it works fine even if I ignore didWriteValueForCharacteristic and just call writeValue in a loop. It seems, with CBCharacteristicWriteWithResponse iOS is doing some internal housekeeping and uses BLE acknowledgments to avoid overwriting current value of the characteristic, therefore the data is being sent in order and without any losses.
Of course, I don't expect to get reliable writes using CBCharacteristicWriteWithResponse, but at least make it work for most cases. If it works on Android, then why shouldn't it work on iOS?
Apple's implementation kind of sucks. All other implementations I've seen have proper flow control. What you could do if you don't want to implement some advanced TCP-like layer on top of BLE is to simply stick with Write Without Response packets but send each 10th packet or so as a Write With Response. Then you won't (with high probability) not get any packet drops. This will probably only be a small performance decrease. You should also increase the MTU to increase the throughput even further.

Latency with Multipeer Connectivity framework

So I've been dumped with a very broken and outdated code base. I'm being asked however to fix only one bug with the latency that occurs when a message is sent between two devices.
The app is for streaming audio to several devices and playing them all at once. The issue is obviously caused when the host sends a "play" message and starts playing itself. This play message is delayed by up to 3 seconds and therefore the clients all end up out of sync.
I've attempted sending a CFAbsoluteTimeGetCurrent(); value to the clients where they then work out the latency but device clocks are very unreliable and I often get negative differences in time despite obviously being positive.
Any idea on how I can combat this? And before suggestions of changing the method entirely, there's isn't much time
Have you considered sending a SYN message along with a local timestamp and then have the per return the timestamp as a ACK message? You can take the difference between the current time and the return time and half it to get a latency.
Source: I did this.

Using Sockets & GameKit at the same time. Drastic socket speed reduction

I've encountered a pretty large issue and have been trying to find a solution for 2 months now with no luck. I've submitted it as a bug, ( https://bugzilla.xamarin.com/show_bug.cgi?id=4910 ) but was hoping maybe someone here could shed some light on the cause of the problem, or suggest a work-around.
In a nutshell, to encounter the error:
Create a basic .Net socket connection between two devices
Create and initialize a GameKit.GKSession object on a least one device.
What occurs is the transfer of the data on the .NET socket becomes erratic and too slow to be usable. I've performed many tests across different devices (see link below) and it affects all of them (iPad 3 affected the least). I've tested it between an iPhone and a Windows PC and it still occurs. MonoTouch's GameKit code is somehow affecting the Socket code.
As you can see from the spreadsheet, speed drop from a few milliseconds to send 1 MB to several minutes to forever.
As soon as the GameKit.GKSession is set to null, any backedlogged data on the socket flows freely again and the sockets act normally once more.
Sample Windows and iOS/MonoTouch Apps demonstrating problem: https://dl.dropbox.com/u/8617393/SocketBug/SocketBug.zip
Test results across different devices (PDF Spreadsheet):
https://dl.dropbox.com/u/8617393/SocketBug/SocketBugTestResults.pdf
This issue seems so hard even Apple decided to circumvent it: http://developer.apple.com/library/ios/#qa/qa1753/_index.html#//apple_ref/doc/uid/DTS40011315
The revealing sentence is this: "This change was made to reduce interference with Wi-Fi."
To assist with anyone that comes across this problem, the issue only manifests itself when the GKSession.Available is set to true. This is required for the device to be discoverable, but not to maintain a connection. With this in mind, a temporary work-around can be used where the GKSession.Available is only set to true when required, and set to false as soon as the connection has been made.
In my scenario, I have a socket connection to the server on both devices. I use this connection to send a message from device A to device B, asking it to become discoverable via bluetooth for the next 10 seconds. As soon as the message is sent, device A begins looking for device B and connects as soon as it finds it. Once the connection is established (or 10 seconds elapses without a connection), device B turns off discoverability and the socket behaves as normal.
In my circumstances, this is an acceptable (pending no real fix) workaround to the problem.

iOS Safari WebSockets : huge latency when sending messages at short intervals

I just found a very annoying thing about using websockets on iOS Safari (iOS 5.0.1). When sending two messages at very close interval (think 30 - 40ms, for example, sending a message at mousedown on a button and one on mouseup) the two messages arrive at 200 to 300ms of interval on the server.
This makes using WebSockets on iOS really painful for making a remote controller for example...
I'm affraid I know the answer, but is there anyway to make it work better ? It seems like it's a bug in the Websockets implementation of Safari but could it also be coming from the WiFi implementation (I hardly think so...) ?
I just found out some kind of workaround, and that the websockets implementation of Safari Mobile behaves even weirder than what I already found out.
While making some ping tests to validate my theory, I realised that I didn't have the problem anymore. Then I tested again with my original code and I had the same problem again.
Then I realised what changed in my code, compared to the ping test : the server never sends anything to the client. So, whenever my server receives a message from the iPhone, he sends a message back to it. That way, the latency disappears. It's really weird and there's probably something to be done to fix that issue, but in the meantime, this will do...

Gamekit Latency

I have the following problem with GKSessions:
Sometimes there is a huge delay when sending data (3-4 seconds sometimes up to 10 seconds) in a client/server application.
If the server sends let's say 10 packets during the delay, those 10 packets are received all at once on the client. The weird thing is that the server still receives packets from the clients during the delay.
This delay seems to be worse in WiFi networks but also happens in bluetooth networks.
Did anyone else encounter such delay spikes when using gamekit?
What could be the source of this issue?
I've been working a lot with gamekit and gksession. I always use the Peer2Peer mode even though some people discourage it. I never experience any kind of delay like the one you describe.
Do you send with GKSendDataReliable or GKSendDataUnreliable? Try switching to the other and see if it changes anything. If you're using GKSendDataReliable then the sending device will wait for a "Received" message from the receiver before sending the next message. This might be the problem.
On your testing devices: Is anything running which might flood the network?
I was testing a multiplayer gamekit based game, and if I had several active devices then suddenly some would stall completely, and I needed to hard reboot (shut down completely and restart) them to make them work again.
If you keep getting in trouble you might want to try a much more low level api: dns-sd https://developer.apple.com/library/mac/#documentation/Networking/Conceptual/dns_discovery_api/Introduction.html
I hope you make it work, good luck!

Resources