iOS使用GCDSocketManager实现长连接
貌似进入2016年就没再更新简书,把写作忘了。罪过。
OK,进入正题,开始今天的技术讲解。
太概念的知识网上有很多,我只做概括和快速并正确的使用。
Socket,即使用套接字连接,实际上是对TCP/UDP的再次封装。
在一般项目中,使用Socket的情况很少,一般都会使用http实现客户端与服务器端的通信。并且是单向的。
但http只能通过客户端向服务器端主动发送网络请求,服务器会对该次请求进行响应,回传给客户端一些数据。如果客户端不主动向服务器端发送网络请求,服务器端是不能主动向客户端做出请求/响应操作的。
所以,为了实现服务器端可以主动向客户端发送请求,我们使用Socket来实现这一需求。
上代码:
1、先到github下载一个非常牛逼的库,地址:https://github.com/robbiehanson/CocoaAsyncSocket
下载到本地后,有两个文件夹:GCD / RunLoop
我个人比较喜欢使用GCD文件。看你擅长哪个技术就选择哪个文件吧。原理都是相同的。
2、将你想使用的文件拖到项目中。
3、一般我们使用第三方库都不会直接使用第三库中某个类或方法,而是对第三方库进行再次封装。.h文件如图:
Snip20160424_21.png
GCDSocketManager是我封装第三方的一个封装类。
对外操作都靠这个类来完成。所以我使用了单例模式供全局使用。
4、.m文件
Snip20160424_23.png
几个需要注意的点:
(1)封装类必须要实现第三方库的GCDAsynSocketDelegate协议
(2)握手次数:客户端和服务器端每次连接传递消息都会校验,校验就会根据握手次数。(socket的原理不多说了)
(3)断开重连定时器:特别需要谨记的是只有当前项目在前台运行时才可以保持长连接的状态,当项目进入后台就会断开长连接,别问为什么。如果你想在程序进入后台扔可以接到服务器主动给你发送的消息,使用推送服务。定时器在这里的作用就是,在当前程序处于前台,如果socket连接失败了要让它自动重连。每隔一段时间让socket自动连接一次。为了运行效率着想,这个时间可以每次进行累加。
(4)重连次数:我的重连次数就是用于时间的累加,第一次连接不上就1秒后重连,第二次连接不上就2秒后重连,以此累加。
5、.m文件的具体实现
Snip20160424_24.png继续下一个
Snip20160424_26.png继续下一个
Snip20160424_27.png继续下一个
Snip20160424_28.png有连接成功,肯定也会有连接失败,以下是对失败事件的处理:
Snip20160424_29.png继续下一个
Snip20160424_31.png连接成功处理完了,连接失败也处理完了。
做事有始有终,有连接,自然也要有断开。
好,以下是对代码的调用时机和代码的使用细节进行一些讲解。
(1)什么时候进行长连?
长连当然是用户登录成功之后需要进行长连。
程序从后台切换到前台也需要进行长连。
所以可以把进行连接的代码写在根控制器中。
(2)什么时候断开长连?
前面说过,程序进入后台是要断开的。所以在Application进入后台时调用的那个生命周期方法里写断开长连的代码。
(3)关于两句很重要的代码
Snip20160424_33.pngtimeout,超时时间。根据实际需求去设置,我这里设置为-1。
tag:发送数据和读取数据的tag值一定不能设置成一样的。
为什么不能设置成一样的呢?举个例子。
在这里tag相当于一个通道,并且在这个通道中只能完成一件事情。
如果这个通道专门用来发送数据的,就给这个通道打个标签,标签值就是1吧。
如果这个通道专门用来读取数据的,就给这个通道打个标签,标签纸就是200把。
数值随便定义,只能你能确保两者的tag值不一样。
但还有一个细节需要注意。
Snip20160424_34.png我在上图代码中再次调用了读取数据的代码,这里的tag值要始终保持一致。
那么在这里写这句代码有啥用呢?
在写这句代码前,我们已经在连接成功的代理方法中写了这句代码。
在上图的代理方法中我可以读取服务器响应的数据。
读取完这一次服务器响应的数据后,下一次服务器再次发送数据我们该怎么读取?
就是通过这句代码,所以在这里再写一次。
这样我们就可以保证每次服务器响应的数据,我们客户端都可以正常读取了。
6、心跳包
心跳包。。就是一个数据包。
每隔一段时间向服务器传输一次你的数据。
当然是使用定时器实现了。代码就不上了哈。
到这里,又出现了一个新问题。
刚才已经说了,程序在前台才能保持长连。
程序进入后台长连就断了。
那么,当程序在后台时依然需要每隔一段时间向服务器发送一次心跳包,这个需求,怎么实现?
请听下回讲解。