关于这几天使用IOS的ASYNCSOCKET完成无限后台的过程_ios gcdasyncsocket 进入后台运行-程序员宅基地

技术标签: iOS网络  asyncSocket  心跳包  

这几天用了下ASyncSocket完成前后台即时通讯,当时有想过用消息推送的技术实现的,可是后来想到消息推送的不可靠性还是算了。于是使用了tcp/ip实现后台主动发送数据给前台的功能。

最开始设计后台的时候,我有考虑到数据量比较大的问题,所以数据大的时候我会使用分包和组包的功能去实现。TCP/IP在传输数据的时候,一般不会大于1500字节,所以我每512字节分了

一个包。然后当一次性数据包接收太多的时候,就出现了粘包的问题。因为我在数据传输的时候使用的是json,每一个分包都是由{}括起来的,所以我就想着在包头上加上一段基本不会重复

的分割字符串,然后服务器接收到分包的时候每次都根据这个字符串分割一下,第一次分割的时候第一行绝对是空字符串 例如:@Hinagiku{“Name”=“桂雏菊”}, 我分割出来结果是:

“”,“桂雏菊”,所以说第一行我就可以直接跳过,每次取分包的时候从第二行开始取。然后后台根据包的ID号,序号进行组包。如果当前分包在5分钟内没有接收完毕,就代表当前分包接收失败

了,要求客户端或服务器重新发送。粘包问题解决完毕之后,我开始实现心跳包功能,当时想的是,每隔1分钟发一次心跳包,服务器放一个线程。每隔几秒钟判断一次,当前的所有TCP连接的

最后一次访问时间是多少号,如果超过了这个时间则断开当前连接。

  实现完成之后,我开始着手无限后台功能的实现。在这里我就不说无限后台有哪几种实现方式了,好麻烦,我使用的VOIP模式。我使用的是在code4app上下载的AsyncSocket这个开源类库,

和GCDAsyncSocket的用法是一样的。开始的时候实现的比较轻松,客户端和服务器的连接和数据传输很快就完成了。后来在实现无限后台的时候,出现了一个很奇怪的问题:我在调试状态运行

程序的时候,程序隐藏到后台的时候的确是可以无限运行的,并且TCP连接没有断开。但是我非调试状态运行的时候,TCP连接在3分钟之后就断掉了。 出现这个问题后我找了整整一天的时候,后来

找到了原因,因为我注释掉了一行代码,所以导致TCP连接会被断开。按道理,实现无限后台有以下几个步骤,首先在plist文件中的Required background modes这一项中新增以下两项(默认

项目中是没有这一项的,需要手动添加):App play audio or streams audio/video using AirPlay和App provides Voice over IP services 。IOS7中没有这么麻烦,可以直接点击项目文件,

勾选以下两项:

然后在AsyncSocket.m中,修改以下方法:

 - (BOOL)createStreamsFromNative:(CFSocketNativeHandle)native error:(NSError **)errPtr

- (BOOL)createStreamsToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr

 

拷贝以下代码到这个方法中

CFReadStreamSetProperty(theReadStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
CFWriteStreamSetProperty(theWriteStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
 CFReadStreamSetProperty(theReadStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
 CFWriteStreamSetProperty(theWriteStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);

 [(NSInputStream *)theReadStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType]; //(这里需不需要加上我不清楚,反正加上也不会报错。。。)
 [(NSOutputStream *)theWriteStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType]; //(这里需不需要加上我不清楚,反正加上也不会报错。。。)

然后在AppDelegate的- (void)applicationDidEnterBackground:(UIApplication *)application这个事件中写入以下代码:

复制代码

- (void)applicationDidEnterBackground:(UIApplication *)application {       BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{            [self heartbeat];    }];    if (backgroundAccepted)    {        NSLog(@"backgrounding accepted");    } }

复制代码


[self heartbeat] 是我写的一个心跳包的方法,这段代码的意思是:每隔10分钟向服务器发送一次心跳包,保证你的TCP连接是正常的。

由于我以前在applicationDidEnterBackground这个事件中写入了这样的代码,所以才会出现那个奇怪的问题:

 

 

复制代码

- (void)applicationDidEnterBackground:(UIApplication *)application {       BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{            [self backgroundhandler];    }];    if (backgroundAccepted)    {        NSLog(@"backgrounding accepted");    }      [self backgroundhandler]; }-(void) backgroundinghandler{NSLog(@"### -->backgroundinghandler");        UIApplication*  app = [UIApplication sharedApplication];    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{        //[app endBackgroundTask:bgTask];    }];    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        while (1) {            NSLog(@"counter:%d", count++);            NSLog(@"timer:%f", [app backgroundTimeRemaining]);            sleep(1);        }    });}

复制代码

这样的代码其实就是为了向后台借更多的时间,但是我们因为使用VOIP后完全不需要借时间了,在TCP监听到消息的时候,程序会从休眠中唤醒10秒左右,所以说在这10秒内我们把接收到的消息处理完就行了。这是网上教程写出来的一个误区,我们使用

 VOIP的时候完全没有必要再去借时间了。

 

我把下面的这段代码改成了上面的那段代码后,我程序挂起到后台以后,我还是收不到服务器发送到的消息。我感觉我的代码没错,到底是哪里出了错误呢。找了几个小时之后,我无意中看到一段提醒:后台监听消息一定要在真机中运行,在模拟器中是监听

不到的。后来我把测试环境改成了ipad,果然就收到消息了,然后发现我自己的愚蠢。因为ipad拿着太麻烦了,所以我用的是模拟器测试的。 哎,以后大家测试这种代码还是都用真机吧,不要跟我一样被坑了。。。

 

本篇文章差不多也就记录到这里了,我还是一个ios新人,有一些理解可能不正确,希望大家指点出来共同学习。



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhaojian3513012/article/details/46792937

智能推荐

C#连接OPC C#上位机链接PLC程序源码 1.该程序是通讯方式是CSharp通过OPC方式连接PLC_c#opc通信-程序员宅基地

文章浏览阅读565次。本文主要介绍如何使用C#通过OPC方式连接PLC,并提供了相应的程序和学习资料,以便读者学习和使用。OPC服务器是一种软件,可以将PLC的数据转换为标准的OPC格式,允许其他软件通过标准接口读取或控制PLC的数据。此外,本文还提供了一些学习资料,包括OPC和PLC的基础知识,C#编程语言的教程和实例代码。这些资料可以帮助读者更好地理解和应用本文介绍的程序。1.该程序是通讯方式是CSharp通过OPC方式连接PLC,用这种方式连PLC不用考虑什么种类PLC,只要OPC服务器里有的PLC都可以连。_c#opc通信

Hyper-V内的虚拟机复制粘贴_win10 hyper-v ubuntu18.04 文件拷贝-程序员宅基地

文章浏览阅读1.6w次,点赞3次,收藏10次。实践环境物理机:Windows10教育版,操作系统版本 17763.914虚拟机:Ubuntu18.04.3桌面版在Hyper-V中的刚安装好Ubuntu虚拟机之后,会发现鼠标滑动很不顺畅,也不能向虚拟机中拖拽文件或者复制内容。在VMware中,可以通过安装VMware tools来使物理机和虚拟机之间达到更好的交互。在Hyper-V中,也有这样的工具。这款工具可以完成更好的鼠标交互,我的..._win10 hyper-v ubuntu18.04 文件拷贝

java静态变量初始化多线程,持续更新中_类初始化一个静态属性 为线程池-程序员宅基地

文章浏览阅读156次。前言互联网时代,瞬息万变。一个小小的走错,就有可能落后于别人。我们没办法去预测任何行业、任何职业未来十年会怎么样,因为未来谁都不能确定。只能说只要有互联网存在,程序员依然是个高薪热门行业。只要跟随着时代的脚步,学习新的知识。程序员是不可能会消失的,或者说不可能会没钱赚的。我们经常可以听到很多人说,程序员是一个吃青春饭的行当。因为大多数人认为这是一个需要高强度脑力劳动的工种,而30岁、40岁,甚至50岁的程序员身体机能逐渐弱化,家庭琐事缠身,已经不能再进行这样高强度的工作了。那么,这样的说法是对的么?_类初始化一个静态属性 为线程池

idea 配置maven,其实不用单独下载Maven的。以及设置新项目配置,省略每次创建新项目都要配置一次Maven_安装idea后是不是不需要安装maven了?-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏43次。说来也是惭愧,一直以来,在装环境的时候都会从官网下载Maven。然后再在idea里配置Maven。以为从官网下载的Maven是必须的步骤,直到今天才得知,idea有捆绑的 Maven 我们只需要搞一个配置文件就行了无需再官网下载Maven包以后再在新电脑装环境的时候,只需要下载idea ,网上找一个Maven的配置文件 放到 默认的 包下面就可以了!也省得每次创建项目都要重新配一次Maven了。如果不想每次新建项目都要重新配置Maven,一种方法就是使用默认的配置,另一种方法就是配置 .._安装idea后是不是不需要安装maven了?

奶爸奶妈必看给宝宝摄影大全-程序员宅基地

文章浏览阅读45次。家是我们一生中最重要的地方,小时候,我们在这里哭、在这里笑、在这里学习走路,在这里有我们最真实的时光,用相机把它记下吧。  很多家庭在拍摄孩子时有一个看法,认为儿童摄影团购必须是在风景秀丽的户外,即便是室内那也是像大酒店一样...

构建Docker镜像指南,含实战案例_rocker/r-base镜像-程序员宅基地

文章浏览阅读429次。Dockerfile介绍Dockerfile是构建镜像的指令文件,由一组指令组成,文件中每条指令对应linux中一条命令,在执行构建Docker镜像时,将读取Dockerfile中的指令,根据指令来操作生成指定Docker镜像。Dockerfile结构:主要由基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令。每行支持一条指令,每条指令可以携带多个参数。注释可以使用#开头。指令说明FROM 镜像 : 指定新的镜像所基于的镜像MAINTAINER 名字 : 说明新镜像的维护(制作)人,留下_rocker/r-base镜像

随便推点

毕设基于微信小程序的小区管理系统的设计ssm毕业设计_ssm基于微信小程序的公寓生活管理系统-程序员宅基地

文章浏览阅读223次。该系统将提供便捷的信息发布、物业报修、社区互动等功能,为小区居民提供更加便利、高效的服务。引言: 随着城市化进程的加速,小区管理成为一个日益重要的任务。因此,设计一个基于微信小程序的小区管理系统成为了一项具有挑战性和重要性的毕设课题。本文将介绍该小区管理系统的设计思路和功能,以期为小区提供更便捷、高效的管理手段。四、总结与展望: 通过本次毕设项目,我们实现了一个基于微信小程序的小区管理系统,为小区居民提供了更加便捷、高效的服务。通过该系统的设计与实现,能够提高小区管理水平,提供更好的居住环境和服务。_ssm基于微信小程序的公寓生活管理系统

如何正确的使用Ubuntu以及安装常用的渗透工具集.-程序员宅基地

文章浏览阅读635次。文章来源i春秋入坑Ubuntu半年多了记得一开始学的时候基本一星期重装三四次=-= 尴尬了 觉得自己差不多可以的时候 就吧Windows10干掉了 c盘装Ubuntu 专心学习. 这里主要来说一下使用Ubuntu的正确姿势Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的开源GNU/Linux操作系统,Ubuntu 是基于DebianGNU/Linux,支..._ubuntu安装攻击工具包

JNI参数传递引用_jni引用byte[]-程序员宅基地

文章浏览阅读335次。需求:C++中将BYTE型数组传递给Java中,考虑到内存释放问题,未采用通过返回值进行数据传递。public class demoClass{public native boolean getData(byte[] tempData);}JNIEXPORT jboolean JNICALL Java_com_core_getData(JNIEnv *env, jobject thisObj, jbyteArray tempData){ //resultsize为s..._jni引用byte[]

三维重建工具——pclpy教程之点云分割_pclpy.pcl.pointcloud.pointxyzi转为numpy-程序员宅基地

文章浏览阅读2.1k次,点赞5次,收藏30次。本教程代码开源:GitHub 欢迎star文章目录一、平面模型分割1. 代码2. 说明3. 运行二、圆柱模型分割1. 代码2. 说明3. 运行三、欧几里得聚类提取1. 代码2. 说明3. 运行四、区域生长分割1. 代码2. 说明3. 运行五、基于最小切割的分割1. 代码2. 说明3. 运行六、使用 ProgressiveMorphologicalFilter 分割地面1. 代码2. 说明3. 运行一、平面模型分割在本教程中,我们将学习如何对一组点进行简单的平面分割,即找到支持平面模型的点云中的所有._pclpy.pcl.pointcloud.pointxyzi转为numpy

以NFS启动方式构建arm-linux仿真运行环境-程序员宅基地

文章浏览阅读141次。一 其实在 skyeye 上移植 arm-linux 并非难事,网上也有不少资料, 只是大都遗漏细节, 以致细微之处卡壳,所以本文力求详实清析, 希望能对大家有点用处。本文旨在将 arm-linux 在 skyeye 上搭建起来,并在 arm-linux 上能成功 mount NFS 为目标, 最终我们能在 arm-linux 里运行我们自己的应用程序. 二 安装 Sky..._nfs启动 arm

攻防世界 Pwn 进阶 第二页_pwn snprintf-程序员宅基地

文章浏览阅读598次,点赞2次,收藏5次。00为了形成一个体系,想将前面学过的一些东西都拉来放在一起总结总结,方便学习,方便记忆。攻防世界 Pwn 新手攻防世界 Pwn 进阶 第一页01 4-ReeHY-main-100超详细的wp1超详细的wp203 format2栈迁移的两种作用之一:栈溢出太小,进行栈迁移从而能够写入更多shellcode,进行更多操作。栈迁移一篇搞定有个陌生的函数。C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 _pwn snprintf

推荐文章

热门文章

相关标签