2013-04-03 7 views
5

ich diesen Code zu Setup geschrieben haben einen Stream mit einem Server:NSStream TCP Keep-alive 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]; 
     } 
} 

Ich bin in der Lage mit dem Server zu verbinden und senden & Daten empfangen. Aber ich möchte überprüfen, ob die Verbindung noch besteht. Wenn ich ein Kabel vom WLAN-Router abziehe, kann ich immer noch Daten im Stream senden und es ist kein Fehler aufgetreten.

Sie können dies auf Anwendungsebene lösen, indem Sie einen Timer verwenden, um eine Nachricht zu senden und zu überprüfen, ob Sie etwas zurück erhalten. Aber Sie können dies auch mit TCP Keep-Alive-Technik auf einer niedrigeren Ebene lösen.

Wie implementiere ich dies mit NStream? Wie kann ich das Prüfintervall einstellen?

Ich nehme an, dass Sie eine NStreamEventErrorOcurred erhalten, wenn der Stream nicht aktiv ist, indem Sie es mit TCP Keep-Alive überprüfen?

Ich habe diesen Beitrag überprüft, aber ich kann es nicht herausgefunden: Keeping a socket connection alive in iOS

Vielen Dank für Ihre Hilfe!

Antwort

1

Diese Delegate-Methode gibt den Stream-Status der Verbindung an. Sie können hier Ihre Verbindungen Status überprüfen

-(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

Ja, ich benutze diese Methode natürlich! Aber wenn ich das UTP-Kabel vom WLAN-Router abziehe, gibt der Stream mir keinen Fehler! Deshalb möchte ich TCP Keep-Alive verwenden. –

+0

sollte es Stream-Status 8 oder 16 drucken. – meth

+0

es gibt mir die Fehlerbeschreibung, wenn ich Fehler Ereignis wie schreiben (NStreamStatus) NStreamEventErrorOccurred: – meth

11

Sie können mit

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

und legen Sie die Socket-Optionen der nativen Socket-Handle erhalten (Sie #include <sys/socket.h> dafür brauchen):

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

Sie könnten diesen Code in die Ereignisbehandlungsfunktion für das Ereignis kCFStreamEventOpenCompleted einfügen:

- (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

Können Sie ein bisschen mehr erklären, was im Code passiert? Ich verstehe es nicht. Ich muss NStream nicht mehr mit den Delegiertenmethoden verwenden? –

+0

@ JimCraane: Sie verwenden immer noch die Delegate-Methoden. Der erste Teil meiner Antwort zeigt, wie der native UNIX-Socket-Deskriptor von NSInputStream abgerufen werden kann. Der zweite Teil zeigt, wie die Option SO_KEEPALIVE gesetzt wird. Ich habe einen dritten Teil hinzugefügt, der zeigt, wie Sie das in Ihren Code integrieren können. - Nach dem Festlegen von SO_KEEPALIVE sollten Sie kCFStreamEventErrorOccurred-Ereignisse erhalten, wenn der Server nicht verbunden ist. –

+0

NSStreamEventOpenCompleted und kCFStreamEventOpenCompleted haben beide einen Wert von 1, also doppelte Groß-/Kleinschreibung. Also habe ich den Code in NStreamEventOpenCompleted eingefügt. Danach starte ich das Programm und stelle eine Verbindung her. Dann trennen Sie das UTP-Kabel vom Router. Jetzt möchte ich einen Fehler innerhalb von 30 Sekunden oder etwas. Wie lautet das Standardzeitintervall für TCP Keep-Alive? Kann ich das ändern? Entschuldigung für all diese Fragen. –

0

Es gibt eine vollständigere Antwort auf eine ähnliche Frage.

Für das Beispiel der Anwendung, die Keep-Alive nach 10 Sekunden beginnt mit dem Senden, sendet keppalive alle 2 Sekunden und schließt den Strom nach 4 Keep Alive ohne Antwort nehmen, einen Blick auf diesen Beitrag: Is it possible to activate TCP keepalive on Apple iOS devices

Es zeigt auch, wie man das Zeitlimit für die erneute Übertragung einstellt, nach dem die Verbindung geschlossen wird.