可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.