2012-07-08 79 views
11

我有以Objective-C編寫的將數據寫入套接字的代碼。服務器在Ubuntu上運行node.js:在iOS中保持套接字連接有效

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分鐘左右?)。我怎樣才能保持這種聯繫?我知道有一個斷開連接,因爲如果我連接到終端下的服務器,同樣的事情發生,我必須保持連接活着。我想象我的代碼中正在發生同樣的事情。謝謝你的幫助!

+0

對於有效的Objective-C代碼,請參考[下面的答案](http://stackoverflow.com/a/25725181)... – Despotovic 2016-02-03 23:08:15

回答

3

我發現如何做到這一點。由於服務器正在運行的node.js,我用

socket.setKeepAlive(true, 2000); 

並以這種方式保持節點的每個插座打開。默認值是false,所以這就是它超時的原因。我希望這對其他人有用。感謝您的回覆,我認爲保持心跳(保持活躍狀態​​)也是一個好主意,但是通過這個本地方法節點來處理它。

+0

您開始使用ios流,現在您正在工作克與套接字對象?你在這裏用什麼樣的api? – 2012-12-26 16:23:01

+1

@ItayLevin他向你展示了他是如何在服務器上完成它的 - 請參閱下面的答案以瞭解如何在iOS上執行此操作。 – 2013-02-10 23:25:43

6

最簡單的答案是嘗試使用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包添加到您的協議和發送平定期打包,以便您可以檢測到連接斷開。

+0

嗯。有沒有一種方法可以在Objective-C中使用上面的API來做到這一點? – Hahnemann 2012-07-09 01:26:35

+0

@Hahnemann:我不太瞭解Objective-C,所以我不知道。然而,我敢打賭,有一個逃生艙來打電話給C庫。 – JimR 2012-07-09 02:57:36

+0

@Hahnemann:看看這裏:http://developer.apple.com/library/ios/DOCUMENTATION/CoreFoundation/Reference/CFStreamConstants/Reference/reference.html#//apple_ref/doc/c_ref/kCFStreamPropertySocketNativeHandle,看看它是否幫助。 – JimR 2012-07-09 03:03:12

3

您需要定期通過連接發送一些垃圾。試試這個:

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

注:更換` 「保持連接!」與任何你想要的協議。唯一的要求是遠程端(套接字服務器)忽略消息。

+0

是否有設置超時限制?我想知道在什麼頻率我應該發送垃圾數​​據 – 2012-07-09 00:14:43

+0

@用戶:連接需要多長時間才能死亡?在此之前安排一下。 – Linuxios 2012-07-09 00:20:12

+1

在某些情況下,您可能想將其視爲套接字服務器上的「心跳數據」,而不是「垃圾」。 ) – 2013-05-17 17:11:48

3

假設一個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)); 
    } 

我張貼這一點,因爲我只花了幾個小時了這一切,要保存別人的努力。

+0

socket_handle,SOL_SOCKET,SO_KEEPALIVE的值是什麼? – Rohan 2013-05-13 11:12:25

+0

man 2 setsockopt或在Xcode文檔視圖中搜索setsockopt。 – 2013-05-13 15:13:14

+2

只有蘋果能夠做出如此簡單,如此複雜的事情。我使用Berkley Sockets編寫了網絡應用程序,並且它比這更簡單。 – deusprogrammer 2015-01-13 18:11:42