2013-04-03 56 views
5

我寫了這個代碼設置一個流與服務器:NSStream TCP保持活躍的iOS

-(void)streamOpenWithIp:(NSString *)ip withPortNumber:(int)portNumber; 
{ 
     CFReadStreamRef readStream; 
     CFWriteStreamRef writeStream; 
     CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)ip, portNumber, &readStream, &writeStream); 

     if(readStream && writeStream) 
     { 
      CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); 
      CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); 

      //Setup inpustream 
      inputStream = (__bridge NSInputStream *)readStream; 
      [inputStream setDelegate:self]; 
      [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
      [inputStream open]; 

      //Setup outputstream 
      outputStream = (__bridge NSOutputStream *)writeStream; 
      [outputStream setDelegate:self]; 
      [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
      [outputStream open]; 
     } 
} 

我能夠連接到服務器併發送&接收數據。但我想檢查連接是否仍然存在。如果我從WiFi路由器斷開連接線,我仍然可以在流中發送數據並且沒有發生錯誤。

您可以通過使用定時器發送一些消息並檢查您是否收到回覆,在應用程序級別解決此問題。但是,您也可以在較低級別上使用TCP Keep-Alive技術來解決此問題。

如何使用NSStream實現這個功能?我怎樣才能設置檢查間隔?

我假設您通過TCP Keep-Alive檢查流時關閉了NSStreamEventErrorOcurred?

我已經檢查了這個職位,但我無法弄清楚: Keeping a socket connection alive in iOS

感謝您的幫助!

回答

1

這個委託方法給出連接的流狀態。你可以檢查你的連接狀態這裏

-(void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event { 
    NSLog(@"Stream triggered."); 
    switch(event) { 
      case (NSStreamStatus)NSStreamEventErrorOccurred: 
     { 

      NSLog(@"%@",[stream streamError].localizedDescription); 

     } 
      break; 
     case NSStreamEventHasSpaceAvailable: { 
      if(stream == outputStream) { 
       NSLog(@"outputStream is ready."); 
      } 
      break; 
     } 
     case NSStreamEventHasBytesAvailable: { 
      if(stream == inputStream) { 

        NSLog(@"data can be read here!"); 

       } 
      } 
      break; 
     } 
     default: { 


      NSLog(@"Stream is sending an Event: %i", event); 
      break; 
     } 
    } 
} 
+0

是的,我當然使用這種方法!但是如果我從無線路由器斷開UTP電纜,流不會給我一個錯誤!這就是爲什麼我想使用TCP保持活着。 –

+0

它應該打印流狀態8或16. – meth

+0

它給了我錯誤描述,當我寫錯誤事件像(NSStreamStatus)NSStreamEventErrorOccurred: – meth

11

你可以得到本地套接字句柄與

CFDataRef socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)(inputStream), kCFStreamPropertySocketNativeHandle); 
CFSocketNativeHandle socket; 
CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket); 
CFRelease(socketData); 

,然後設置套接字選項(需要#include <sys/socket.h>此):

int on = 1; 
if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) { 
    NSLog(@"setsockopt failed: %s", strerror(errno)); 
} 

您可以將此代碼放入kCFStreamEventOpenCompleted事件的事件處理函數中:

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event { 
    switch (event) { 
     case kCFStreamEventOpenCompleted: 
      if (stream == self.inputStream) { 
       CFDataRef socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)(stream), kCFStreamPropertySocketNativeHandle); 
       CFSocketNativeHandle socket; 
       CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket); 
       CFRelease(socketData); 

       int on = 1; 
       if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) { 
        NSLog(@"setsockopt failed: %s", strerror(errno)); 
       } 
      } 
      break; 

     /* ... other cases ... */; 
    } 
} 
+0

你能解釋一下代碼中發生了什麼嗎?我不明白。我不必使用NSStream與代理方法了嗎? –

+0

@JimCraane:你仍然使用委託方法。我的答案的第一部分顯示瞭如何從NSInputStream獲取本機UNIX套接字描述符。第二部分顯示如何設置SO_KEEPALIVE選項。我添加了第三部分,展示了我認爲如何將它集成到代碼中。 - 設置完SO_KEEPALIVE後,如果服務器斷開,您應該會收到kCFStreamEventErrorOccurred事件。 –

+0

NSStreamEventOpenCompleted和kCFStreamEventOpenCompleted的值均爲1,因此重複大小寫。所以我把代碼放在NSStreamEventOpenCompleted中。之後,我運行程序並建立連接。斷開UTP電纜與路由器的連接。 現在我想要一個類似30秒內的錯誤或什麼的。 TCP Keep-Alive的標準時間間隔是多少?我可以改變它嗎?對不起,這些問題。 –