NSStream TCP Keep-alive iOS

匿名 (未验证) 提交于 2019-12-03 01:06:02

问题:

I have written this code to setup a stream with a server:

-(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];        } } 

I am able to connect to the server and send & receive data. But I want to check if the connection is still there. If I disconnect a cable from the wifi router, I still can send data in the stream and no error occurred.

You can solve this on application level by using a timer to send some message and check if you receive something back. But you can solve this also with TCP Keep-Alive technique on a lower level.

How do I implement this with NSStream? How can I set the checking interval?

I assume that you get a NSStreamEventErrorOcurred when the stream is down by checking it with TCP Keep-Alive?

I have checked this post, but I can't figure it out: Keeping a socket connection alive in iOS

Thanks for your help!

回答1:

You can get the native socket handle with

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

and then set socket options (you need to #include for this):

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

You could put this code in the event handler function for the kCFStreamEventOpenCompleted event:

- (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 ... */;     } } 


回答2:

this delegate method gives the stream status of connection. you can check your connections status here

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


回答3:

There is a more complete answer to a similar question.

For the example of the app that starts sending keepalive after 10 seconds, sends keppalive every 2 seconds and closes the stream after 4 keepalives with no reply, take a look at this post: Is it possible to activate TCP keepalive on Apple iOS devices

It also shows how to set retransmission timeout after which the connection is closed.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!