转自:http://blog.csdn.net/missautumn/article/details/17102067

如果你的应用程序需要在设备休眠的时候还能够收到服务器端发送的消息,那我们就可以借助VOIP的模式来实现这一需求。但是如果的应用程序并不是正真的VOIP应用,那当你把你的应用提交到AppStore的时候基本上会被苹果Reject. 但是如果你的应用是企业内部发布的或者你只想了解其中的原理,那该文也许对您会有所帮助。
一、在iOS中如何应用VOIP
VOIP程序需要稳定的网络去连接和它相关的服务,这样它才能接到来电和其他相关的数据。系统允许VOIP程序被挂断并提供组件去监听它们的sockets,而不是在任意时候都处于唤醒状态。设置VOIP应用程序步骤如下:
 
A、 添加UIBackgroundModes中的VOIP键值
大多数VOIP应用需要设置后台audio 应用去传递音频,因此你应该设置audio 和voip两个键值。
如果只是想通过VOIP来达到socket在休眠状态下维持长连接那只需要象上图一样设置VOIP即可。
B、 为VOIP设置一个应用程序socket
为了使应用程序在后台时保持稳定的连接,你必须tag你的主 通讯socket专门应用于VOIP,tagging这个socket来告诉系统,它必须在你的应用程序中断时接管这个socket。这个切换本身对于你 的应用程序时透明的,当新的数据到达socket的时候,系统会唤醒应用程序,并将socket的控制权返回给应用程序,这样应用程序就可以处理新来的数据。
 
你只需要tag用于voip服务的socket,这个 socket用来接收来电或者其他相关的数据来保持你的VOIP服务的连接。根据收到的信息,这个socket要决定下一步的动作。比如一个来电,你会想 弹出一个本地的通知来告知用户;对于其他不是那么关键的数据,你可能会想悄悄的处理这些数据并让系统将应用程序重新中断。
 
在IOS中,sockets是用流或者更高级的结构,设置一个VOIP的socket,你只需要在通常的设置中添加一个特殊的key来标明这个接口是用于连接VOIP服务的,下表列出了流的接口和设置:
 
设置流接口用于voip接口
 
1、NSInputStream 和NSOutputStream 
对于 Cocoa streams, 使用 setProperty:forKey: 方法添加
 
NSStreamNetworkServiceType  
属性给 stream.   
改属性的值设为  
NSStreamNetworkServiceTypeVoIP.  
2、NSURLRequest 
对于 URL loading system, 使用 setNetworkServiceType:
method of your NSMutableURLRequest object to set the network service  
type of the request. The service type should be set to  
NSURLNetworkServiceTypeVoIP. 
3、CFReadStreamRef和CFWriteStreamRef
For Core Foundation streams, use the CFReadStreamSetProperty or  
CFWriteStreamSetProperty function to add the kCFStreamNetwork-  
ServiceType property to the stream. The value for this property should be  
set to kCFStreamNetworkServiceTypeVoIP. 
(注意:当设置socket的时候,你需要在你的主信号通道中设置合适的service type key。当设置声道时,不需要设置这个key)
 
由于,VOIP应用程序需要一直运行以确保收到来电,所以如果程 序通过一个非零的exit code退出,系统将自动重启这个应用程序(这种退出方式可以发生在内存压力大时终止程序运行)。尽管如此,中断应用程序会release所有的 sockets,包括那个用于连接voip 服务的socket。因此,当程序运行时,它需要一直从头创建socket。
C、 在移出后台之前,调用setKeepAliveTimeout:handler:方法去建立一个定期执行的handler,你的应用程序可以运行这个handler来保持服务的连接
为了防止断连,voip程序需要定期被唤醒去检查它的服务。为了容易实现这个行为,IOS通过使用(UIApplication setKeepAliveTimeout:handler:)方法建立一个特殊的句柄。你可以在 applicationDidEnterBackground方法中建立该句柄。一旦建立,系统至少会在超时之前调用该句柄一次,来唤醒你的应用程序。
 
这个keep-alive handler在后台执行,必须尽快的返回参数,它有最多30秒的时间来执行所需的任务,如果这段时间内句柄没有返回,那么系统将终止应用程序。
 
当你建立了handler之后,确定应用程序所需的最大超时。系统保证会在最大超时之前调用handler,但是这个时间是不确定的,所以你的handler必须在你申明的超时之前做好执行程序的准备。
 
二、通过GCDAsyncSocket来实现休眠状态下的长连接:
 
1、在创建socket并且成功连接上远程服务器的delegate中执行下述代码
  1. - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)connectedPort{  
  2.     [socket performBlock:^{  
  3.         [socket enableBackgroundingOnSocket];  
  4.     }];  
  5. }  
2、在ApplicationDidEnterBackground方法中调用setKeepAliveTimeOut以保持长连接
  1. BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];  
  2.  if (backgroundAccepted)  
  3.  {  
  4.       NSLog(@"VOIP backgrounding accepted");  
  5.  }  
参考:
1、XMPP中长连接问答
 
2、GCDAsyncSocket实现后台长连接的VOIP问答
 
3、后台运行(内容比较杂,但还是很有参考价值)
 
4、有一篇国内的关于VOIP以及后台程序的博文(内容还是比较杂--还是英文的,估计只能由博主自己看懂,仅做参考)
http://blog.csdn.net/gnicky/article/details/7452418
 
5、iOS socket编程基础
 
6、一篇StackOverflow.com中的问答,其中对iOS中对VOIP的解释比较详细

If you want to let your VOIP application run in background , except those base settings in plist file, you need a TCP socket who's property is set to VOIP, than the iOS system will take care this socket for you, when your application enter background , every thing was 'sleep' except that tcp socket. and if VOIP server send some data thought that TCP socket, your application will be awake up for 10 secs. during this time, you can post a local notification.


Only Tcp socket can be set as VOIP Socket. But from i know , mostly VOIP application are based on UDP socket. if you do not want to separate the control socket from the data socket. you should create another tcp socket which is focus on 'awake' your application , and from my personal experience , it's very hard to keep this 'awake' signal and the real sip control signal synchronize, the application always miss the sip invite request.

So,the best way is separating the sip control single from the UDP data socket , make it as a tcp socket , this is the best solution , but never use tcp socket to transfer voice data.

Another dirty way: keep the application awake all the time. As i said , each TCP single the application received thought that 'VOIP' tcp socket , will keep application awake for 10 seconds, so at the end of this duration(after 9 secs) , you can send a response to the server to ask for another signal , when the next signal arrived, the application will be awake again,after 9 secs , send response again. keep doing this, your application will awake forever.
 
7.CocoaAsyncSocket

[转] iOS应用中通过设置VOIP模式实现休眠状态下socket的长连接的更多相关文章

  1. iOS应用中通过设置VOIP模式实现休眠状态下socket的长连接

    如果你的应用程序需要在设备休眠的时候还能够收到服务器端发送的消息,那我们就可以借助VOIP的模式来实现这一需求.但是如果的应用程序并不是正真的VOIP应用,那当你把你的应用提交到AppStore的时候 ...

  2. ios系统中各种设置项的url链接

    ios系统中各种设置项的url链接 在代码中调用如下代码:NSURL*url=[NSURL URLWithString:@"prefs:root=WIFI"];[[UIApplic ...

  3. ios开发中全局变量设置和调用方法

    ios开发中,全局变量设置和调用方法如下:在AppDelegate.h文件中设置全局变量:@interface ***AppDelegate{NSString *myName;}@property ( ...

  4. [ios2]ios系统中各种设置项的url链接

    在代码中调用如下代码:(ps: ios 5.0 以后不可用)NSURL*url=[NSURL URLWithString:@"prefs:root=WIFI"];[[UIAppli ...

  5. IOS 应用中从竖屏模式强制转换为横屏模式

    在 iPhone 应用里,有时我们想强行把显示模式从纵屏改为横屏(反之亦然),CocoaChina 会员 “alienblue” 为我们提供了两种思路 第一种:通过人为的办法改变view.transf ...

  6. [iOS] iOS系统中各种设置项的url链接

    在代码中调用如下代码:NSURL*url=[NSURL URLWithString:@"prefs:root=WIFI"];[[UIApplication sharedApplic ...

  7. 在IOS应用中从竖屏模式强制转换为横屏模式

    http://www.cnblogs.com/mrhgw/archive/2012/07/18/2597218.html 在 iPhone 应用里,有时我们想强行把显示模式从纵屏改为横屏(反之亦然), ...

  8. IOS中快速集成短信SDK验证开发(SMSSDK),IOS开发中如何设置手机验证码

    [转载请注明出处] sdk是别人的,我只是下载来集成一下. smssdk下载网站:http://www.mob.com/(也有其他很多网站有类似SDK,譬如https://www.juhe.cn/等等 ...

  9. 如何在 iOS 8 中使用 Swift 实现本地通知(下)

    在上集中,我们已经构建了一个简单的待办列表应用(to-do list app),这个应用可以在待办项过期时通过本地通知提醒用户.现在,我们要在之前的基础上添加以下功能:应用图标角标上显示过期待办项的数 ...

随机推荐

  1. 【上下界网络流】bzoj2502: 清理雪道

    模型:无源汇有上下界可行流 LJN:模板题吧 Description        滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的 ...

  2. ERROR 1045 (28000): Access denied for user 'xxx'@'localhost' (using password: YES) MYSQL 新建用户 无法登录 问题解决方法

    使用mysql ,出现新建账户无法登录问题 查看 user列表中,有部分账户没有设置密码,将全部重新设置一遍密码,然后还是无法登录. 使用命令 update user set password=pas ...

  3. MyBatis的mapper.xml文件的参数问题:org.apache.ibatis.builder.IncompleteElementException: Could not find parameter map

    配置参数类型有两种选择,即:parameterType和parameterMap 不管参数是否是基本数据类型还是map类型,都是使用parameterType. 版权声明:本文为博主原创文章,未经博主 ...

  4. 树莓派开发板入门学习笔记1:[转]资料收集及树莓派系统在Ubuntu安装

    参考教程(微雪课堂):http://www.waveshare.net/study/portal.php 树莓派实验室: http://shumeipai.nxez.com/2014/12/21/us ...

  5. stm32之PWM学习

    下图是一个STM32普通PWM形成的图形原理说明 自动重装载寄存器(ARR)用于确定波形的频率(即周期).捕获比较寄存器(CCRx)(用于确定占空比的) PWM的工作过程如下:首先ARR寄存器里面的值 ...

  6. BZOJ 4368: [IOI2015]boxes纪念品盒

    三种路径,左边出去左边回来,右边出去右边回来,绕一圈 绕一圈的路径最多出现一次 那么绕一圈的路径覆盖的点一定是左边半圈的右边和右边半圈的左边 枚举绕一圈的路径的起始点(一定要枚举,这一步不能贪心),更 ...

  7. LA 4253 Archery 二分

    题意: x轴上方有若干条平行于x轴的线段 在x轴的区间\([0, \, W]\)内找一点发射一条射线,使其穿过所有线段. 问是否存在这样的点. 分析: 我们二分射线端点的坐标,将线段按纵坐标从小到大排 ...

  8. 遍历Request.QueryString

    Request.QueryString 返回的是 NameValueCollection, 而NameValueCollection实现了IEnumerable的GetEnumerator方法,只是G ...

  9. Leetcode26--->Remove Duplicates from Sorted Array(从排序数组中移除相同的元素)

    题目: 给定一个排序数组,移除重复出现的元素,保证每个元素最终在数组中只出现一次.返回新数组的长度length; 要求:不能分配额外的一个数组使用,必须使用原地排序的思想,且空间复杂度为O(1) 举例 ...

  10. Xshell设置登录会话

    新建会话 点击用户登录验证输入账号密码 如果是公钥登录,选择pubulic key登录