2010-11-16 50 views
0

嗯,至少意外對我來說...這是情況: 我用下面的代碼打開一個套接字:iPhone插座被關閉意外

CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef)ipaddress , 3333,&readStream, &writeStream); 
if(!CFReadStreamOpen(readStream) || !CFWriteStreamOpen(writeStream)) 
{ 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Connection error" 
       message:@"There has been a connection error, please ensure your internet connection is working" 
       delegate:self 
      cancelButtonTitle:@"OK" 
      otherButtonTitles:nil]; 

    [alert show]; 
    return; 
} 

這一切都很好,我做的下一件事就是建立回調:

CFStreamClientContext ctxt = {0,(void*)NULL,NULL,NULL,NULL}; 
static const CFOptionFlags kReadNetworkEvents = kCFStreamEventEndEncountered | 
kCFStreamEventErrorOccurred | 
kCFStreamEventHasBytesAvailable | 
kCFStreamEventOpenCompleted | 
kCFStreamEventNone; 


CFReadStreamSetClient(readStream, kReadNetworkEvents, ReadStreamClientCallBack, &ctxt); 
CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 

而且工作得很好,我將列出回調方法來完成:

static void ReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType type, void *clientCallBackInfo) { 
switch (type) 
{ 
    case kCFStreamEventEndEncountered: 
    { 
    break; 
    } 
    case kCFStreamEventErrorOccurred: 
    break; 
    case kCFStreamEventHasBytesAvailable: 
    { 
    [this stopListen]; 
    UInt8 buffer[1024]; 
    int count = CFReadStreamRead(stream, buffer, 1024); 
    CFStreamStatus status = CFReadStreamGetStatus(this.readStream); 
    CFErrorRef error = CFReadStreamCopyError (this.readStream); 
    CFStringRef errorCode = CFErrorCopyDescription(error); 
    // Bunch of other irrelevant code 

現在出了什麼問題:只要我留在應用程序中,所有這些代碼都可以正常工作,即使我退出應用程序並再次輸入它仍然可以正常工作。如果我在應用程序打開時進入待機狀態,它也可以正常工作。但是,如果我退出應用程序,將手機置於待機狀態,讓手機退出待機狀態,然後重新進入應用程序,即使我已100%確定沒有發送字節,立即使用eventtype kCFStreamEventHasBytesAvailable調用回撥。如果我然後調用CFReadStreamRead,它會向我返回-1,因爲這意味着發生了一個錯誤,我計算出錯誤代碼是57,這意味着套接字已關閉。

我是否忽略了iPhone上套接字編程的某些方面?我必須承認我是新手。在應用程序外(並進入待機狀態),是否可以保持TCP套接字處於打開狀態? 我試圖再次調用CFReadStreamOpen,它返回false給我。

我迷路了,請幫忙!

在此先感謝在4.0以上的多任務處理功能

+0

你在使用什麼操作系統版本? – slf 2010-11-16 14:13:34

+0

我正在使用OS 4.1,但是昨天我做了一個3.2版本,並且發生了錯誤。 – loconero 2010-11-16 14:21:39

回答

1

部分需要額外的編碼支持保持連接活着,並執行任務的背景。您可能只是OS收回這些資源的受害者,因爲您沒有在適當的時間「選擇加入」這些資源。

本節介紹backgrounding的基礎:

http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

具體如下:

準備處理連接 失敗在基於網絡的 插座。該系統可能會拆除 套接字連接,而您的 應用程序因任意 原因而被暫停。只要您的 基於套接字的代碼爲 準備了其他類型的網絡故障,例如 作爲丟失信號或網絡 轉換,這應該不會導致 任何異常問題。當您的 應用程序恢復時,如果在使用套接字時遇到 失敗,則只需 重新建立連接。

然而,有三個很特別的東西,你可以在後臺做的,如果你這樣做,你應該申報他們在您的Info.plist是一個很好的應用公民。這三個值在UIBackgroundModes財產,他們是audiolocationvoip

您可以通過註冊一個塊(即使它不是guarunteed你會得到它)這樣的要求更多的時間爲你的任務:

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    UIApplication* app = [UIApplication sharedApplication]; 

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
     [app endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }]; 

    // Start the long-running task and return immediately. 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     // Do the work associated with the task. 

     [app endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }); 
} 

另請參閱A Short Practical Guide to Blocks以獲得快速瀏覽,Concurrency Programming Guide獲取更多詳細信息。

+0

非常感謝!這對我有效。我所做的就是捕獲-1錯誤並執行新的登錄順序。但是我打算給用戶提供通知(由tcp消息發起),而不是在應用程序中,例如即時通訊...有沒有辦法保持我的流在應用程序外打開並工作? – loconero 2010-11-16 15:24:27

+0

推送通知是一個單獨的API,請參閱http://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction/Introduction.html – slf 2010-11-16 20:26:55