I have an app that creates a TCP socket and receives data from different kinds of hardware. The majority of my customers are happy users, but some have the problem that the TCP connection is interrupted after some time (could be 30 seconds or 5 minutes).
I'm using the CFStreamCreatePairWithSocketToHost - approach, and do all my handling in the "handleEvent" method.
I've got some customers loggings of the failure, and I get this event:
ErrorOccurred "The operation couldn’t be completed. Socket is not
connected (Code = 57)"
After a couple of successful reconnections I might get this event when I try to reconnect:
ErrorOccurred "The operation couldn’t be completed. No route to host
(Code = 65)"
The easy explanation would be that their devices that create the WiFi network and stream the data are bad, but some customers are also using other apps that connects to the same devices, and those apps don't lose their connections.
I'm running out of ideas what to change or improve to solve the problem.
I've checked that the size of the data available, and it's never more than 1 sentence, so it's not like any buffers are running full.
I actually also have a small test app that does nothing but connect to the broadcasting device and log the received data - and that also loses the connection for these customers.
I also tried to use AsyncSocket instead but I am having the same problem.
My hairs are turning grey... :-) Any help would be appreciated.
A lot of testing, logging and speculating finally solved the case.
The only thing the customer had to do was to lower the baud rate, and the problem disappeared.
Case closed.
Related
I'm currently developing a react native app in combination with a device. The device and the app communicate via BLE. So far everything works as expected but I'm having issues with the connection stability of the iOS app and the device. What would happen is that the device would connect and I can update some characteristics but it would regularly either disconnect with a CBErrorDomain 7 or the response for a write would timeout. The implementation on the app or device side does not seem to be the problem as Android works stable and the device also disconnects when connecting with the LightBlue app.
I've already updated the BLE connection parameters as suggested here:
https://developer.apple.com/library/archive/qa/qa1931/_index.html.
This has increased the stability but did not resolve the problems completely. I've tried playing around with the values but so far no luck.
The current set of parameters we are using are:
conn_min_interval: 15
conn_max_interval: 15
conn_latency: 0
supervision_timeout: 2000
adv_min_interval: 1285
adv_max_interval: 1285
My question now would be if somebody has an idea what other things I could check or which parameter to tune?
Are you checking the maximumWriteValueLength and making sure your writes are smaller than this? A likely cause of your problems is overwhelming the device and it fails to keep up with sending ACKs. What version of Bluetooth does your device support, and does it implement DLE (Data Length Extension)?
Your conn_min_interval and conn_max_interval are suspicious. Asking for 15ms with no leeway is likely to negotiate to 30ms instead. (See 41.6 Connection Parameters) Is your device comfortable with being re-negotiated to something other than 15ms? Can your device actually keep up with 15ms and no connection latency if it does get that? I'm betting it can't. Try setting your connection interval to 30ms (or even a bit slower), and you might even try setting your connection latency to 1 to make the connection a bit more forgiving (though I'd focus more on slowing the CI than increasing latency; increasing latency would be more of a hack in this case).
All my suspicions are around your peripheral not keeping up with its side of the connection. If you have any synchronous activities in response to the data, you need to make sure that it's not blocking your BLE stack from sending the required responses.
Finally, I've found the answer to my problem. The problem was that the pairing procedure of the BLE server was faulty and thus iOS was unable to have a stable connection. Now that this is fixed the connection is very stable.
I'm still unsure why iOS was able to have any communication at all without the pairing but I hope that this helps some people in the future.
So sum up, I have a device communicating via ble to my application. The application uses Corebluetooth to handle the connection and communication.
The problem:
When a device goes out of range it will disconnect -> it calls the diddisconnect() function where I check if its timed out and call the central.connect again.
it will then start the connection and immediately on some devices(only iOS14) at the moment, it will go to didfailtoconnect with an error saying:
"Error Domain=CBErrorDomain Code=15 "Failed to encrypt the connection, the connection has timed out unexpectedly." UserInfo={NSLocalizedDescription=Failed to encrypt the connection, the connection has timed out unexpectedly."
Only seem to exist on iOS14 devices as far as I have seen.
I also tested blocking signals, if i block signals from device the issue is not apparent. if I block signals from phone, the issue is apparent. Not sure how this is, feels like they both trigger timeout.
May be problem elsewhere aswell but it seem to handle fine on my iOS13 device.(mainly tested on 4 phones, 2 on each version)
Also to clarify, the application is acting as the central, and the device as the peripheral.
If I interpret the error message correctly from CBErrorEncryptionTimedOut (15), it means that the devices initiated a connection, then, suddenly after the iOS device initiated the encryption procedure, the connection unexpectedly died.
So it should be treated more or less the same way as CBErrorConnectionTimeout (6).
If this happens all the time, you should use a BLE sniffer to see what's going on; maybe it's some bug in iOS.
I'd like to find out if a Wi-Fi has internet connection or not. Sometimes our devices are connected with Wi-Fi, but the Wi-Fi doesn't have an internet connection.
NWPathMonitor or Connectivity thirdparty. I tried it, but it is not fool proof.
I know I can write a method to ping a server, but this is a very ineffective and costly affair.
Any ideas?
The only way to know for sure if a network has an Internet connection is to try and make a connection to the Internet. There is nothing on the device that you can query to get the answer.
Even if there were it would have to resort to polling/pinging since connectivity can change at any instant.
A WiFi connection can transition from no-Internet to Internet when the user completes a Hotspot login form. A WiFi connection can transition from Internet to no-Internet if the upstream Internet connection fails in some way. A WiFi connection may be connected to the Internet but not be able to communicate with the specific host your app needs due to a routing failure or some other issue.
For all of these reasons Apple actively discourages "pre flight" checks. Even if a check passes a network operation can still fail due to a change in network status that occurred a microsecond later. It is also unnecessary overhead as it is generally a safe assumption that most devices have some sort of Internet connection most of the time, particularly if the device is an iPhone.
You need to handle errors anyway. Just try the operation and see what happens. If there is no network connection it will fail pretty quickly.
If you want to provide more feedback to the user then you could begin actively checking Internet connectivity with exponential back off in response to a connection error.
That way your app isn't constantly "pinging".
You can also use the error to start a process that uses SCNetworkReachability to check connectivity for you. Rather than using that framework directly, particularly if you are writing in Swift, you might like to use something that wraps it and makes it more accessible like Ashley Mills' Reachability.swift
I've searched the web extensively but haven't found a good answer to this.
Im writing a socket based application in C++ using posix sockets on iOS/Android.
When switching from wifi->3g, SOMETIMES the socket goes dead without giving any errors when reading/writing.
I can use the reachability API on iOS (and similar on android) to detect when the network switches.
I am destroying/recreating the socket when this occurs. The problem is if the socket is alive, the server will receive the signal when I close the socket. If the server receives the close signal, it will assume the client disconnected intentionally and notify others about this, which is not what I want. If the socket is dead, the server doesn't receive this signal and everything is OK.
How do other people handle this scenario? I really don't want to use a timeout to detect this.
Why does it only sometimes die too? And how can I tell the socket is actually dead?
Just to close this issue, this is the approach I'm taking.
When switching networks, I'm sending a ping-and-reconnect packet to the server, AND creating a new socket.
Which ever responds first, I close the other connection.
Required a bit of server side changes to handle this correctly too
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.