Iphone 监控连接状态&;装卸液滴

Iphone 监控连接状态&;装卸液滴,iphone,ios,nsstream,cfnetwork,Iphone,Ios,Nsstream,Cfnetwork,我已经实施了一个有效的解决方案,请参见下面我的评论 您好,感谢您抽出时间阅读这篇文章 我正在开发一个应用程序,它可以连接到一个硬件设备,该设备可以播放自己的AdHoc WiFi网络。我能够通过CFNetwork与NSStream的免费桥接连接到设备、发送字节和接收字节。我使用的是相当“事实上”的流打开代码,流代理正在报告它应该报告的NSStreamEvents 在初始化与设备的连接时,我可以看到输入流和输出流都打开(NSSTREAVENTOPENCOMPLETED),并且随着硬件设备不断发送“H

我已经实施了一个有效的解决方案,请参见下面我的评论

您好,感谢您抽出时间阅读这篇文章

我正在开发一个应用程序,它可以连接到一个硬件设备,该设备可以播放自己的AdHoc WiFi网络。我能够通过CFNetwork与NSStream的免费桥接连接到设备、发送字节和接收字节。我使用的是相当“事实上”的流打开代码,流代理正在报告它应该报告的NSStreamEvents

在初始化与设备的连接时,我可以看到输入流和输出流都打开(NSSTREAVENTOPENCOMPLETED),并且随着硬件设备不断发送“HELLO!”,输入流上立即有字节可用(NSSTREAVENTHSBYTESAVAILable)

在NSSTREATEVENTHSBYTESAVABLE的事件中,我从inputStream读取数据并记录如下:

   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;
正如所料,当我的设备连接时,我有一个恒定的“LOG--devicesaid:xxxx”流。但是,如果我断开设备与电源的连接,我不会收到任何类型的流事件;日志记录只是一起停止

我试图通过在viewDidLoad中启动backgroundTimer来解决这个问题,它每0.1秒尝试从inputStream读取一次。如果无法读取,则布尔值
deviceIsConnected
设置为
FALSE
,我会显示一条警报,通知用户他们与设备的连接已断开

这种方法已经被证明是相当不可靠的,而且对于完成一项看似简单的检测套接字连接关闭的任务来说也是一种非常不公平的方法。如果我理解正确,NSStream类本质上是底层BSD套接字体系结构之上的“中间人”或抽象层

断开硬件设备与电源的连接,就好像走出了设备内置WiFi芯片的范围。这不是一个“真实世界”的测试,好像你正从设备上走开,你不会突然失去连接;相反,inputStream接收的数据将缓慢恶化,从而导致“网络警报”弹出窗口在设备在“已连接”和“未连接”之间跳跃时持续闪烁

我想实现某种KeepAlive处理程序,但我缺乏使用iPhone/iOS/BSD套接字的经验,这严重阻碍了我的工作。如果你们中任何一位优秀的个人能够提供一个方法的基本示例(可能是在计时器上运行的,我认为我在正确的路径上!),该方法可以检测到套接字变得不可用并继续尝试重新建立连接,我将永远感激。我孜孜不倦地搜索了谷歌,找到了一些有希望的想法,但都没能成功实施

CocoaASyncSocket能回答我所有的问题/挫折吗


再次感谢您抽出时间阅读本文。我希望我已经清楚地解释了我的问题和我想要的解决方案。如果您有任何问题,请随时提问,我会尽力回答。

CocoaAsyncSocket也会有同样的问题(尽管这是一个伟大的项目)。TCP连接正常工作,但只有当另一端“按规则”断开连接时,才会检测到断开。如果线路断开(关闭设备,超出范围…),您需要一些机制来检测。这是客户的任务

考虑使用
NSTimer
是正确的

有几种方法可以解决这个问题,主要取决于一件事:是您的设备自己发送数据(成功连接后),还是您的应用程序必须请求数据

但解决方案基本相同。成功连接后,您将创建一个可重复的NSTimer。您还需要某种
dataAge
变量。此计时器(可称为
connectionMonitor
)在每次触发时都会增加
dataAge

如果
dataAge
太大(>5s),则会破坏连接(以及计时器),并重新开始连接过程

当然,
dataAge
应该在每次从设备获取数据时重置

您还应该处理事件
nsstreamventerrocurred
nsstreamventendecountered
:可能需要销毁
connectionMonitor
并重新启动连接过程


您可能知道本教程,但以防万一:

我之前解释的理论(见注释)确实有效。我现在能够使用以下逻辑成功地监控设备连接的状态(请理解,以下代码块存在于整个应用程序中)。我能够确定设备不可用的确切时间;可能是由于缺少WiFi连接,或者设备断电

// Define two socket objects, a "Main" socket and "Observer" socket

asyncSocketMain = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
dispatch_queue_t secondaryQueue = dispatch_get_current_queue();
asyncSocketObserver = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:secondaryQueue];

// On application launch, attempt to open asyncSocketMain
[asyncSocketMain connectToHost:host onPort:port withTimeout: 2.0 error:&error]

// Determine which socket object is connecting in the didConnectToHost method
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSString *currentSocketId = (NSString *)sock;

// Determine Which Socket Object is Connecting...
if(currentSocketId == (NSString *)asyncSocketMain)
{
    NSLog(@"Main Socket has Connected!");
    connectionIsOpening = false;  // Allow for Future Reconnect Attempts
    deviceIsConnected   = true;   // Allow Connection Monitoring

    // If the Main Socket has been attempting to reconnect, stop doing that!
    if(reconnectTimer)
    {
        [ reconnectTimer invalidate ]; // Stop the reconnectTimer
        reconnectTimer = nil;          // And also set its value to nil
    }
    [ self setupMonitorTimer ];   // Begin Monitoring the Connection
}else{
    if(currentSocketId == (NSString *)asyncSocketObserver)
    {
        NSLog(@"Observer Socket attempting connection! Socket: %@", sock);
    }else{
        NSLog(@"ALERT ALERT -- UNKNOWN SOCKET CONNECTING!!!");
    }
}
} // close void
现在,当观察者套接字尝试连接时,将抛出一个错误。这就是我能够确定当前连接的方式。如果已连接
asyncSocketMain
套接字,观察者将始终抛出错误代码7。如果
asyncSocketObserver
在尝试连接时超时,则表示设备已关机、超出范围或无法使用(例如,用户手机未连接到正确的WiFi网络)。在这种情况下,所有“监视”都应该停止,并为
asyncSocketMain
启动计时器以尝试重新连接

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{


NSString *connectingSocket = (NSString *)sock;

// Figure out hte Error Code Info  
NSError * error;
error = err;
NSInteger errorNum = error.code;


if(connectingSocket == (NSString *)asyncSocketMain)
{
    // This may occur if the app is opened when the device is out of range
    NSLog(@"The MAIN SOCKET Encountered an Error while Connecting! [ CODE: %d ]", errorNum);
    [ asyncSocketMain disconnect ]; // Disconnect the Main Socket to allow for reconnects
    connectionIsOpening = false;    // Allow Main Connection Attempts
    deviceIsConnected = false;      // Device is NOT CONNECTED -- Do NOT RUN MONITORING
    if(!reconnectTimer)
    {
        NSLog(@"Starting the reconnectTimer");
        [ self setupReconnectTimer ];   // Start attempting to reconnect
    }else{
        NSLog(@"Reconnect Timer is Already Running!");
    }
}
else
if(connectingSocket == (NSString *)asyncSocketObserver)
{
    switch (errorNum)
    {
        case 1:
            // Not much to do here...
            NSLog(@"OBSERVER ERROR - There is already a socket attempting to connect!");
            break;

        case 2:
            // Not much to do here...
            NSLog(@"OBSERVER ERROR - Event 2");
            break;

        case 3:
            // Time Out -- The device is out of range. Halt observer connection attempts, disconnect the main
            // socket object, then proceed to attempt to reconnect with the main socket.
            NSLog(@"OBSERVER ERROR - Connected Timed out -- Device not available!!!!");

            // The Observer Socket Timed out -- It's time to start reconnecting
            connectionIsOpening = false; // Allow Main Connection Attempts
            deviceIsConnected   = false; // Device is NOT CONNECTED - DO NOT RUN MONITORING and ALLOW CONNECTION ATTEMPTS
            if(monitorTimer)
            {
                // Stop trying to reconnect with the observer socket, thus allowing the Main socket to connect
                NSLog(@"Stopping the Monitoring Method...");
                [monitorTimer invalidate];
                monitorTimer = nil;
            }else{
                NSLog(@"Connection Monitoring already halted!");
            }

            // If the reconnectTimer is not running (it shouldnt be, otherwise something is wrong) then go ahead and run it
            // This will attempt to reconnect asyncSocketMain
            if(!reconnectTimer)
            {
                NSLog(@"Starting the reconnectTimer");
                [ asyncSocketMain disconnect ]; // Deallocate the main socket to allow for reconnects
                [ self setupReconnectTimer ];
            }else{
                NSLog(@"Reconnection Attempts are already happening! [ reconnectTimer: %@ ]",reconnectTimer);
            }

            break;

        case 7:
            NSLog(@"OBSERVER ERROR - The Main Socket is Already Connected!");
            break;
    }
}
else{
    NSLog(@"An Unknown Socket Connection Encountered and Error...");
}
} // end void
为了便于参考,我将所有数据都写在
asyncSocketMain
上。每当
deviceIsConnected=TRUE
时,
asynchsocketobserver
对象总是试图在计时器上连接

这可能不是监视连接的最优雅的方式,但确实有效。一旦我断开设备的电源,
asyncSocketObserver
超时,然后(根据代码)停止所有“连接”