在 iOS 中保持套接字连接处于活动状态



我用Objective-C编写了以下代码,将数据写入套接字。服务器正在运行节点.js在 Ubuntu 之上:

NSString *url = @"anIPAddress";        
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;            
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)url, 9000, &readStream, &writeStream);
self.inputStream = (NSInputStream *)readStream;            
self.outputStream = (NSOutputStream *)writeStream;
[self.inputStream setDelegate:self];            
[self.outputStream setDelegate:self];            
[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];            
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];            
[self.inputStream open];            
[self.outputStream open];

我能够连接到服务器并发送信息。但是我注意到几分钟后连接超时(我想是 5 分钟左右?如何保持此连接处于活动状态?我知道存在断开连接,因为如果我连接到终端下的服务器,也会发生同样的事情,我必须保持该连接处于活动状态。我想在我的代码中也发生了同样的事情。感谢您的帮助!

最简单的答案是尝试使用 SO_KEEPALIVE 套接字选项。

如果没有数据在端点之间流动,则很难检测到断开的连接,这使得此选项在某些方面毫无用处,因为它不使用数据来检测断开的连接。 但是,很容易添加到代码中以查看。 添加它,看看是否有帮助...

这就是它在 C 或 C++ 中完成的方式

int opt = 1;
// Get the native socket handle from your socket class here...
int socket_handle = getNativeSocketHandle( self.outputStream );
/*Enabling keep alive*/
if( setsockopt( socket_handle, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) ) < 0 )
{
   // failed setting socket option
}

不那么简单的答案是将ping数据包添加到您的协议中并定期发送该 ping 数据包,以便您可以检测到断开的连接。

我找到了如何做到这一点。由于服务器正在运行node.js,我使用了

socket.setKeepAlive(true, 2000);

通过这种方式,节点保持每个套接字打开。默认值为 false,因此这就是它超时的原因。我希望这对其他人有用。感谢您的回复,我认为保持心跳(保持活动状态)也是一个好主意,但使用这种本机方法节点可以处理它。

假设一个NSOutputStream *oStream;

在 iOS 上,这样做:

#if 1 // Using CF
CFDataRef data = (CFDataRef)CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)oStream, kCFStreamPropertySocketNativeHandle);
if(data) {
    CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)CFDataGetBytePtr(data);
    CFRelease(data);
#else // Using Foundation
NSData *data = (NSData *)[oStream propertyForKey:(__bridge NSString *)kCFStreamPropertySocketNativeHandle];
if(data) {
    CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)[data bytes];
#endif
    NSLog(@"SOCK HANDLE: %x", socket_handle);
    /*Enabling keep alive*/
    if( setsockopt( socket_handle, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) ) < 0 )
    {
       NSLog(@"Yikes 2: failed to set keepalive! ERRNO: %s", strerror(errno));
    }

我发布这个是因为我只是花了几个小时来解决这一切,想节省其他人的精力。

您需要定期通过连接发送一些垃圾。试试这个:

NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:240 target:self selector:@selector(timerMethod:) userInfo:[NSNumber numberWithInt:sockfd] repeats:YES];

然后在self中声明:

-(void)timerMethod:(NSTimer*)t
{
  send([[t userInfo] intValue], "Keepalive!", 11, 0);
}

注意:将"保持活动状态!"替换为您想要的协议。唯一的要求是远程端(套接字服务器)忽略消息。

相关内容

  • 没有找到相关文章

最新更新