如何在后台维护VOIP套接字连接?

如何在后台维护VOIP套接字连接?

问题描述:

我的应用程序要求:由于某些原因,我应该维护套接字连接以在服务器推送时触发本地通知,而无需使用推送通知(APN)。所以我使用iPhone的VOIP后台功能来维护套接字连接。如何在后台维护VOIP套接字连接?

1.我已经为VOIP配置了一个流,以保持套接字连接在后台运行,那么应该设置什么样的超时值? 一旦超时过期,套接字连接会终止吗? 如何让我的应用程序始终监听套接字?

客户端流的配置如下,

NSString *urlStr = @"http://192.168.0.108"; 
NSURL *website = [NSURL URLWithString:urlStr]; 
CFReadStreamRef readStream; 
CFWriteStreamRef writeStream; 
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 1234, &readStream, &writeStream); 

CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); 
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);  

NSInputStream *inputStream = (NSInputStream *)readStream; 
NSOutputStream *outputStream = (NSOutputStream *)writeStream; 
[inputStream setDelegate:self]; 
[inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; 
[outputStream setDelegate:self]; 
[outputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; 
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
[inputStream open]; 
[outputStream open]; 

2.我应该重新在处理程序applicationDidEnterBackground流:

[[UIApplication sharedApplication] setKeepAliveTimeout:86400 handler:^(void) 
{ 

    if (inputStream) 
     [inputStream close]; 
    if (outputStream) 
     [outputStream close]; 


    urlStr = @"http://192.168.0.108"; 
    website = [NSURL URLWithString:urlStr]; 
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 1234, &readStream, &writeStream); 
    CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); 
    CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);  
    inputStream = (NSInputStream *)readStream; 
    outputStream = (NSOutputStream *)writeStream; 
    [inputStream setDelegate:self]; 
    [inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; 
    [outputStream setDelegate:self]; 
    [outputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; 
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [inputStream open]; 
    [outputStream open]; 

    }]; 

3.说出我的服务器重新启动和应用程序在后台,我如何确保连接? 如果我的iPhone中的Wi-Fi连接或如果我终止服务器应用程序,连接将被关闭,那么应该采取什么措施使我的应用程序按预期工作?

+1

你在这里包含的代码是它的工作代码吗? – 2014-02-06 07:15:00

你还需要确保你已经设置你的plist文件

<key>UIBackgroundModes</key> 
<array> 
    <string>voip</string> 
</array> 

插座将通过iOS的,而你的应用程序是在后台进行管理。只要套接字中有可用数据,应用程序就会收到CPU时间。所以在runLoop我检查HT

在我的情况下,信令协议是在一个单独的线程工作,所以我纺runLoop我自己

// Start runloop 
    while (!m_needStop) 
    { 
    CFRunLoopRun(); 
    } 

并在必要时停止它:

m_needStop = true; 
    { 
    QAutoLock l(m_runLoopGuard); 
    if (m_runLoop != NULL) 
     CFRunLoopStop(m_runLoop); 
    } 

对于runLoop插座我已经安装了处理函数安排他们到runLoop前:

int nFlags = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; 
    CFStreamClientContext context; 
    context.info = this; 
    context.version = 0; 
    context.release = NULL; 
    context.retain = NULL; 
    context.copyDescription = NULL; 

    if (!CFReadStreamSetClient(m_readStream, nFlags, NotificationProtocolHandler::ReadStreamCallback, &context)) 
    { 
    ReleaseStreams(); 
    return false; 
    } 

    if (!CFWriteStreamSetClient(m_writeStream, nFlags, NotificationProtocolHandler::WriteStreamCallback, &context)) 
    { 
    ReleaseStreams(); 
    return false; 
    } 

这些都将被调用的函数,当你套接字曾经为了你而即使一些信息的后台应用程序:

void NotificationProtocolHandler::ReadStreamCallback(CFReadStreamRef stream, 
                CFStreamEventType eventType, 
                void *clientCallBackInfo) 
{  
    NotificationProtocolHandler* handler = (NotificationProtocolHandler*)clientCallBackInfo; 
    switch (eventType) 
    { 
    case kCFStreamEventOpenCompleted: 
     break; 

    case kCFStreamEventHasBytesAvailable: 
     handler->ProcessInput(); 
     break; 

    case kCFStreamEventErrorOccurred: 
     handler->ProcessConnectionError(); 
     break; 

    case kCFStreamEventEndEncountered: 
     handler->ProcessConnectionError(); 
     break; 

    default: 
     break; // do nothing 
    } 
} 

void NotificationProtocolHandler::WriteStreamCallback(CFWriteStreamRef stream, 
                 CFStreamEventType eventType, 
                 void *clientCallBackInfo) 
{ 
    NotificationProtocolHandler* handler = (NotificationProtocolHandler*)clientCallBackInfo; 

    switch (eventType) 
    { 
    case kCFStreamEventOpenCompleted: 
     handler->ProcessOutputConnect(); 
     break; 

    case kCFStreamEventCanAcceptBytes: 
     handler->ProcessReadyToWrite(); 
     break; 

    case kCFStreamEventErrorOccurred: 
     handler->ProcessConnectionError(); 
     break; 

    case kCFStreamEventEndEncountered: 
     handler->ProcessConnectionError(); 
     break;  

    default: 
     break; // do nothing 
    } 
} 

为了使服务器知道客户端还活着我们发送ping命令服务器每10分钟一次,因此KeepAlive处理程序设置为600.您可以使用其他值来保存电池,但这会使检测客户端和服务器端的断开连接变得更糟。并且会增加断开和重新连接之间的时间。

BOOL scheduled = [app setKeepAliveTimeout:pingTimeout handler:^{ // Schedule processing after some time interval  

    SchedulePing(0); 
} 

凡SchedulePing(0)将如下执行:

StartLongBGTask(); 
if (avoidFinishBgTask != NULL) 
    *avoidFinishBgTask = true; 
m_pingTimer = CreateTimer(pingTimeout, PingTimerCallback); // result is ignored 

而且StartLongBGTask是

m_bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{ 
    [[UIApplication sharedApplication] endBackgroundTask:m_bgTask]; 
    m_bgTask = UIBackgroundTaskInvalid; 
}]; 

这是确保应用程序不会在发送前被暂停需要ping并等待来自服务器的ping响应。另外,如果套接字已经断开连接,则可能发生需要重新连接的过程,这需要一些时间并需要在后台运行。

但是,确保在不再需要后台时正确释放后台任务。当超过bg超时时,其他明智的应用程序将被系统杀死。

+0

刚刚偶然发现一篇文章说,一个应用程序被拒绝,因为它没有提供任何IP语音服务,但使用VoIP背景模式。对此有何想法?因此,如果我正在开发即时消息应用程序,并且即使在后台也希望套接字仍然活着,即使我不支持任何语音功能,我是否仍然可以使用上述方法? – Roshit 2012-04-19 20:41:28

+0

您是否已批准您的应用程序? - 我处于类似的情况,但幸运的是我可以使用企业分布 – gheese 2012-10-05 14:22:59

+0

也对此感到好奇。如果你有一些故事,请留言! – Nailer 2013-02-25 21:37:47

苹果已经详细介绍了国际上这个官documentation.You可以在这里找到https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/AdvancedAppTricks/AdvancedAppTricks.html

按照文档

有用于实施VoIP应用几个要求:

1.将UIBackgroundModes键添加到您应用的Info.plist文件中。将此密钥的值设置为包含voip字符串的数组。

2.为VoIP使用配置其中一个应用套接字。

3.在移动到后台前,调用setKeepAliveTimeout:handler:方法来安装一个定期执行的处理程序。您的应用可以使用此处理程序来维护其服务连接。

4.配置您的音频会话以处理往返使用中的转换。

5.为确保iPhone上更好的用户体验,请使用核心电话框架来调整您的行为与基于蜂窝电话的关系;请参阅核心电话框架参考。

6.为确保VoIP应用的良好性能,请使用系统配置框架检测网络更改并尽可能让您的应用休眠。

在UIBackgroundModes键中包含voip值可让系统知道它应该允许应用程序根据需要在后台运行以管理其网络套接字。此键还允许您的应用播放背景音频(尽管仍然鼓励包含UIBackgroundModes键的音频值)。带有此密钥的应用程序在系统引导后立即在后台重新启动,以确保VoIP服务始终可用。有关UIBackgroundModes键的更多信息,请参阅信息属性列表键参考。