I have implemented a working solutions, please see my comment below
Hello, and thank you for taking the time to read this post!
I'm developing an app which connects to a hardware device which broadcasts its own AdHoc WiFi network. I am able to connect to the device, send bytes, and receive bytes via CFNetwork toll-free bridging with NSStream. I am using the rather "de-facto" stream opening code and the stream delegate is reporting NSStreamEvents as it should.
Upon initializing my connection to the device, I can see both input and output streams open (NSStreamEventOpenCompleted) and as the hardware device is constantly sending "HELLO!", there are immediately BytesAvailable on the inputStream (NSStreamEventHasBytesAvailable).
In the case event for NSStreamEventHasBytesAvailable, I read data from the inputStream and log it as so:
case NSStreamEventHasBytesAvailable:
NSLog(@"CASE LOG -- NSStreamEventHasBytesAvailable");
uint8_t buffer[256];
int len;
while ([inputStream hasBytesAvailable]) {
//NSLog(@"LOG -- inputStream hasBytesAvailable");
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSLog(@"Length of inputStream Bytes -- %i",len);
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
// This global boolean affects the rest of the apps functionality. Buttons are not able to send bytes to the hardware device if this boolean is FALSE.
deviceIsConnected = true;
// If buttons to send bytes are disabled due to lack of network connection on appLaunch, then go ahead and show them, allowing the user to send bytes to the hardware device
if(buttonsAreDisabled == true)
{
[ self setButtonVisibility:true ];
// Reset the status of the "No Connection" Alert
connectionAlertShown = false;
}
// Log the incoming data
if (nil != output) {
NSLog(@"LOG -- device said: %@", output);
}
}
}
break;
As expected, I have a constant stream of "LOG -- device said: xxxx" while my device is connected. However, if I disconnect the device from its power source, I do not receive any sort of Stream Event; the logging simply stops all together.
I have attempted to remedy this issue by starting a backgroundTimer in my viewDidLoad, which every 0.1 seconds attempts to read from the inputStream. If it is not able to read, then the boolean deviceIsConnected
is set to FALSE
and I display an alert informing the user that their connection to the device has dropped.
This method has proven rather unreliable, and also a very ungraceful way of going about a seemingly simple task of detecting the closing of a socket connection. If I understand correctly, the NSStream class is essentially a "Middle man" or abstraction layer above the underlying BSD Socket Architecture.
Disconnecting the hardware device from its power source is simulating walking out of range of the device's onboard WiFi chip. This is not a "real world" test, as if you are physically walking away from the device, you will not suddenly lose connection; rather, the data received by the inputStream will slowly deteriorate thus causing the "Network Alert" popup to continuously flicker as the device jumps between "connected" and "not connected".
I would like to implement some sort of KeepAlive handler, but my lack of experience with iPhone / iOS / BSD Sockets is hindering me severely. If any of you wonderful individuals could provide a basic example of a method (likely running on a timer, I think I'm on the right path there!) that can detect a socket becoming unavailable and proceed to attempt to reestablished the connection, I would be eternally grateful. I have tirelessly searched Google and found a few promising ideas, but haven't been able to successfully implement any of them.
Could CocoaASyncSocket be the answer to all my questions / frustrations?
Thank you again for taking the time to read over this post. I hope I have provided a clear explanation of my problem and my desired solution. Should you have any questions, please feel free to ask and I will do my best to answer.
My previously explained theory (see comments) has indeed worked. I am now able to successfully monitor the status of the device connectivity with the following logic (please understand that the following chunks of code exist throughout the application). I am able to determine the exact moment the device becomes unavailable; be it due to lack of WiFi connectivity, or the device losing power.
Now, when the observer socket attempts to connect, an error will be thrown. This is how I am able to determine current connectivity. The observer will always throw error code 7 if the
asyncSocketMain
socket is already connected. IfasyncSocketObserver
times out when attempting to connect, that means the device is either powered off, out of range, or otherwise unavailable (e.g. the users phone is not connected to the correct WiFi network). In this case, all "monitoring" should be halted, and a timer is started forasyncSocketMain
to attempt reconnects.For reference, I write all data out on
asyncSocketMain
. TheasyncSocketObserver
object is always attempting to connect on a timer, wheneverdeviceIsConnected = TRUE
.This may not be the most graceful way of monitoring the connection, but it does indeed work. As soon as I disconnect power from my device,
asyncSocketObserver
times out, which then (as per code) halts all "connection monitoring" and beings a "reconnect" timer, which is then invalided as soon as connection is established.Thank you again @rokjarc for your helpful knowledge and input, I hope the semi-pseudo code I have provided here (which does indeed function as intended!) aids some other developer, as this is something that I have struggled with a for at least a week!