zoukankan      html  css  js  c++  java
  • IOS 后台保持连接

    当iphone应用程序进行网络编程时,切到后台后,socket连接会断掉,ios的设计就是这样。

    但是好在apple公司也没有那么绝,还是有一些东西可以在后台运行的(backgroundmodes),

    比如:音乐 GPS  Voip Locationupdates等

    我们以voip为例

    这里我们可以将NSStream指定voip的属性,从而可以避免程序切到后台的时候socket连接中断。

    可以分为两步:

    1.在info.plist文件中,增加voip选项,如

    2. 设置NSStream的属性,如

    在IOS中,sockets是用流或者更高级的结构,设置一个VOIP的socket,你只需要在通常的设置中添加一个特殊的key来标明这个接口是用于连接VOIP服务的,下表列出了流的接口和设置:

    设置流接口用于voip接口

    NSInputStream 和NSOutputStream 对于 Cocoa streams, 使用 setProperty:forKey: 方法添加

    NSStreamNetworkServiceType 属性给 stream. 改属性的值设为 NSStreamNetworkServiceTypeVoIP.

    [readStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType];

    这样,当程序切到后台的时候,这个socket连接还会被保持。

    另外,iphone都是通过wifi或者gprs上网的,那么当socket连接空闲一段时间后,这个连接有可能被路由器关闭,为了保持连接,我们需要不停发送'心跳包'(保持连接状态)。

    由于iphone上的程序切到后台后,程序会被挂起,那么也就无法定时发送心跳包,所以这个问题只能由服务端来解决。普通的办法就是服务器每隔一定时间给每个客户端发送一个心跳包,以维持这个连接。每当客户端接收到心跳包的时候,客户端会被IOS唤醒,获得一小段CPU时间,然后再次进入挂起状态。

    解决方法:

    通过设置以下属性可以保持socket连接和数据的继续传输

    1.需要在Info.plist文件中添加UIBackgroundModes中的VOIP键值;

    2.设置流属性

    CFReadStreamRef和CFWriteStreamRef通过如下方法设置kCFStreamNetworkServiceType属性为kCFStreamNetworkServiceTypeVoIP;

    CFReadStreamSetProperty(theReadStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);

    CFWriteStreamSetProperty(theWriteStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);

    NSInputStream 和NSOutputStream通过如下方法设置NSStreamNetworkServiceType属性为NSStreamNetworkServiceTypeVoIP;

    [self.stream setProperty: NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType];

    3.这里有一个问题,就是客户端是通过心跳来和服务端保持连接,心跳是由定时器触发的,当我退到后台以后,定时器方法被挂起,那么通过如下设置来在后台运行定时器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    - (void)applicationDidEnterBackground:(UIApplication *)application{
     
        UIApplication*   app = [UIApplication sharedApplication];
        __block    UIBackgroundTaskIdentifier bgTask;
        bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
            dispatch_async(dispatch_get_main_queue(), ^{
                if (bgTask != UIBackgroundTaskInvalid)
                {
                    bgTask = UIBackgroundTaskInvalid;
                }
            });
        }];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                if (bgTask != UIBackgroundTaskInvalid)
                {
                    bgTask = UIBackgroundTaskInvalid;
                }
            });
        });
    }
  • 相关阅读:
    SDN2017 第四次作业
    SDN2017 第三次实验作业
    软件工程实践2017 个人作业——软件工程实践总结作业
    sdn2017 第三次作业
    Golang 探索对Goroutine的控制方法
    SDN2017 第二次实验作业
    SDN2017 第二次作业
    Redis在游戏服务器中的应用
    手机游戏开发
    手机游戏开发
  • 原文地址:https://www.cnblogs.com/mafeng/p/6586865.html
Copyright © 2011-2022 走看看