2010-11-16 47 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