iOS的即时通讯问题

80 阅读7分钟

www.jianshu.com/p/8d7fcb790…

(IM 即为InstantMessaging)

第一种方式,采用第三方的IM服务,这个对于目前的大多数公司都是采用这种方式。类似云信、环信、融云、LeanCloud等,一般来说,第三方服务商IM的底层协议基本上是都是TCP协议(传输控制协议)

缺点:定制化程度太高,很多东西不可控,而且比较贵.

优点:简单,只需要简单集成就行,甚至于界面也可以直接套用

第二种方式:我们自己去实现

1)首先面临的就是传输协议的选择,TCP还是UDP?

TCP(传输控制协议)

a.建立连接,形成传输数据的通道

b.在连接中进行大数据的传输(数据大小不受限制)

c.通过三次握手完成连接,是可靠协议,安全送达,丢包率低。

d.必须建立连接,效率会稍低。(因为需要建立联系,可能相对效率就会低一点)

三次握手协议:

建立一个TCP连接,需要三次握手。

第一次:客户端发送syn包(syn=j)到服务器,并进入syn_Send状态,等待服务器确认。

第二次:服务器接受到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个syn(syn=k)包,即syn+ACK包,此时服务器进入一个SYN_RECV状态。

第三次:客户端接收到服务端的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务端进入established状态,完成三次握手。

然后两者之间才开始传输数据。如果主动断开连接,需要经过“四次握手”。

四次握手的细则:

blog.csdn.net/eric0318/ar…

 UDP(报文协议,例如短信)

 a.只管发送,不确认对方是否接收到。

 b.将数据及源和目的封装成数据包中,不需要建立连接。

 c.每个数据报的大小限制在64K之内。

 d.因为无需连接,因此是不可靠协,丢包率高。

 e.不需要建立连接,速度快。

2)其次是我们需要去选择使用哪种聊天协议:

  • 基于Scoket或者WebScoket或者其他的私有协议、

  • MQTT

  • 还是广为人诟病的XMPP?

基于Scoket原生:代表框架 CocoaAsyncSocket。

基于WebScoket:代表框架 SocketRocket。

基于MQTT:代表框架 MQTTKit。

基于XMPP:代表框架 XMPPFramework。
或者不采用第三方封装的库,直接基于OS底层Scoket去实现我们的自定义封装。

socket是TCP/IP协议的封装,socket本身并不是协议,而是一个调用接口(API),通过socket,我们才能使用TCP/IP协议。

3)我们是自己去基于OS底层Socket进行封装还是在第三方框架的基础上进行封装?

4)传输数据的格式,我们是用Json、还是XML、还是谷歌推出的ProtocolBuffer?

5)我们还有一些细节问题需要考虑,例如TCP的长连接如何保持,心跳机制,Qos机制,重连机制等等...当然,除此之外,我们还有一些安全问题需要考虑。

其实,总的来说,一般的小公司还是采用TCP的方式,除非公司的技术比较成熟,就可以考虑采用UDP协议,因为他需要做的事情太多了。

首先需要搞清楚的是,其中MQTT和XMPP为聊天协议,它们是最上层的协议,而WebScoket是传输通讯协议,它是基于Socket封装的一个协议。而通常我们所说的腾讯IM的私有协议,就是基于WebScoket或者Scoket原生进行封装的一个聊天协议。 所以说到底,iOS要做一个真正的IM产品,一般都是基于Scoket或者WebScoket等,再之上加上一些私有协议来保证的。

一般的IM的结构解析:

    我们使用socket,轻易的实现了进程之间的通信(跨网络的)。想想,如果没有socket,我们要直面TCP/IP协议,我们需要去写多少繁琐而又重复的代码,那么socket到底是什么呢?

1.socket到底是什么?

blog.csdn.net/yeyuangen/a…

2.接下来就是实现了,首先我们首先我们不基于任何框架,直接去调用OS底层-基于C的BSD Socket去实现,它提供了这样一组接口。

客户端:

  1. 客户端调用 socket(...) 创建socket;

  2. 客户端调用 connect(...) 向服务器发起连接请求以建立连接;

  3. 客户端与服务器建立连接之后,就可以通过send(...)/receive(...)向客户端发送或从客户端接收数据;

  4. 客户端调用 close 关闭 socket;

服务端:

1.服务器调用 socket(...) 创建socket;

2.服务器调用 listen(...) 设置缓冲区;

3.服务器通过 accept(...)接受客户端请求建立连接;

4.服务器与客户端建立连接之后,就可以通过 send(...)/receive(...)向客户端发送或从客户端接收数据;

5.服务器调用 close 关闭 socket;

什么叫心跳:

心跳就是用来检测TCP连接的双方是否可用。 那又会有人要问了,TCP不是本身就自带一个KeepAlive机制吗?

这里我们需要说明的是TCP的KeepAlive机制只能保证连接的存在,但是并不能保证客户端以及服务端的可用性.****

比如:

某台服务器因为某些原因导致负载超高,CPU 100%,无法响应任何业务请求,但是使用 TCP 探针则仍旧能够确定连接状态,这就是典型的连接活着但业务提供方已死的状态。

这时候心跳机制就很有作用了。

  • 我们客户端发起心跳Ping(一般都是客户端),假如设置在10秒后如果没有收到回调,那么说明服务器或者客户端某一方出现问题,这时候我们需要主动断开连接。

  • 服务端也是一样,会维护一个socket的心跳间隔,当约定时间内,没有收到客户端发来的心跳,我们会知道该连接已经失效,然后主动断开连接。

其实做过IM的小伙伴们都知道,我们真正需要心跳机制的原因其实主要是在于国内运营商NAT超时。

pingpong机制:

而国内的运营商一般NAT超时的时间为5分钟,所以通常我们心跳设置的时间间隔为3-5分钟。

很多小伙伴可能又会感觉到疑惑了,那么我们在这心跳间隔的3-5分钟如果连接假在线(例如在地铁电梯这种环境下)。那么我们岂不是无法保证消息的即时性么?这显然是我们无法接受的,所以业内的解决方案是采用双向的PingPong机制


当服务端发出一个Ping,客户端没有在约定的时间内返回响应的ack,则认为客户端已经不在线,这时我们Server端会主动断开Scoket连接,并且改由APNS推送的方式发送消息。

同样的是,当客户端去发送一个消息,因为我们迟迟无法收到服务端的响应ack包,则表明客户端或者服务端已不在线,我们也会显示消息发送失败,并且断开Scoket连接。

还记得我们之前CocoaSyncSockt的例子所讲的获取消息超时就断开吗?其实它就是一个PingPong机制的客户端实现。我们每次可以在发送消息成功后,调用这个超时读取的方法,如果一段时间没收到服务器的响应,那么说明连接不可用,则断开Scoket连接



重连机制:

我们自己主动去断开的Scoket连接(例如退出账号,APP退出到后台等等),不需要重连。其他的连接断开,我们都需要进行断线重连。一般解决方案是尝试重连几次,如果仍旧无法重连成功,那么不再进行重连。