voip socket 后台长连接

voip socket 后台长连接

最近在做ios切后台保持voip后台长连接的功能,在网上查了很多资料,看起来倒是说得简单,但是我做完之后,切后台还是不能保持,前台能连上,切后台几秒就断了,麻烦实现长连接的高手帮我看看,哪里出问题了。
1.在 xxxx Info.plist 添加 以支持 后台运行
UIBackgroundModes

voip

2.IOS实现socket有三种方法:NSURL,NSStream,CFStream,由于我的底层socket是用C++写的,所以我用CFStream

void EnterBackground()
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;



//用CFStreamCreatePairWithSocket 在已有的socket 上创建输入输出流
CFStreamCreatePairWithSocket(NULL, m_socket, &readStream, &writeStream);


//设置属性kCFStreamNetworkServiceTypeVoIP
CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);

// runloop没写,不知道有没有影响?
CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream);
}



//接下来我在applicationDidEnterBackground:方法里调用上面写的函数
- (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.
//在这里我调用了上面自己写的方法void EnterBackground(),不知道有没有问题??
[app endBackgroundTask:bgTask];

bgTask = UIBackgroundTaskInvalid;

});
}




在 xxxx Info.plist 添加 以支持 后台运行 
UIBackgroundModes 
 
voip 
 
2.在 applicationDidEnterBackground 中设置存活回调(系统保证在600内会调用一次 //todo send keep live 
[[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ //todo send keep live }]; 
*注:这里最少600秒否则失败 
3. 在 applicationWillEnterForeground 中取消存活回调 
[[UIApplication sharedApplication] clearKeepAliveTimeout]; 

4. 创建 网络连接 ,这一步 可以按官方文档提供的三种方法全创建,并设置属性(如NSStreamNetworkServiceTypeVoIP.....) 
但这里 说一下移植原有 c/c++网络层的代码的会有两个问题: 
a>IOS并没有提到直接把一个存在的socket设置后台接收属性 
b>一般原有c/c++网络层的程序 很多会使用一个线程阻塞接收数据,而 ios里的流(NSStream) 如果阻塞read 过75秒后就超时,还不能更改这个值,而用IOS推荐的方式(Run-Loop)使用NSstream 又会改变程序结构(收到事件方式); 

下面是解决方案,关键在用CFStreamCreatePairWithSocket 在已有的socket 上创建输入输出流 
CFReadStreamRef readStream; 
        CFWriteStreamRef writeStream; 
        CFStreamCreatePairWithSocket(NULL, m_socket,  &readStream, &writeStream); 
        miStream = (NSInputStream *)readStream; 
        moStream = (NSOutputStream *)writeStream;       
        
        if(miStream == nil) 
            return gloox::ConnStreamError; 
        [miStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType]; 
        [moStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType]; 
        
       // [miStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
      //  [moStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
        [miStream open];//这两句不写可能都能正常工作,我没试 
        [moStream open];//这两句不写可能都能正常工作,我没试 

其实 上面的代码只做一件事,就是告诉IOS 在当前应用不在前台的时候 接管这个socket, 
其他的(原c/c++代码)都不动,该用socket recv就recv  该send就send,不用管 
miStream和mStream ,只是别忘了关闭连接的时候释放它们; 


你可能感兴趣的:(后台)