iOS端IM开发从入门到填坑_第1页
iOS端IM开发从入门到填坑_第2页
iOS端IM开发从入门到填坑_第3页
iOS端IM开发从入门到填坑_第4页
iOS端IM开发从入门到填坑_第5页
已阅读5页,还剩15页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、im 的实现方式拿来主义,使用第三方im 服务im的第三方服务商国内有很多,底层协议基本上都是基于tcp 的,类似有网易云信、环信、融云、极光im 、leancloud 、云通讯 im (腾讯)、云旺im (阿里)、容联云、小能、美洽等等,技术也相对比较成熟,提供后台管理和定制化的ui,拿来主义,半小时集成。缺点也很明显:定制化程度太高,需要二次开发,很多东西我们不可控,关键是太贵了。如果 im 对于 app 只是一个辅助功能,如客服系统、消息推送等,也基本够用。自己动手,切合业务自己实现几乎所有互联网im 产品都用服务器中转方式进行消息传输。自己去实现也会面临许多选择:1、传输协议的选择:t

2、cp 还是 udp ?2、选择哪种聊天协议进行开发:mqtt 、xmpp 、基于 socket 原生或 websocket 的私有协议?3、传输数据的格式:用json 、还是 xml 、还是谷歌推出的protocolbuffer?4、我们还有一些细节问题需要考虑,例如tcp 的长连接如何保持,心跳机制,qos机制,重连机制等等。另外,还有一些安全问题需要考虑。一、传输协议的选择移动端 im 的传输协议选型:tcp 还是 udp ?tcp:基于连接的可靠协议的全双工的可靠信道,有流量控制、差错控制等,占用系统资源较多,传输效率相对低udp :基于无连接的不可靠协议,没有足够的控制手段,传输效率高

3、,有丢包问题tcp 和 udp 的最完整的区别https:/ udp 协议开发成本较高,容易各种丢包或乱序,一般小公司或技术不成熟或即时性要求不高的公司,多用tcp 开发。qq-im的私有协议:登录等安全性操作使用tcp 协议,好友之间发消息主要使用udp 协议,内网传输文件采用了p2p 技术,另外腾讯还用了自己的私有协议,来保证传输的可靠性。二、聊天协议的选择首先我们以实现方式来切入,基本上有以下四种实现方式:基于 socket原生: 代表框架 cocoaasyncsocket。基于 websocket:代表框架 socketrocket。基于 mqtt :代表框架 mqttkit 。基于

4、xmpp :代表框架 xmppframework。以上四种方式都可以不使用第三方框架,直接基于os 底层 socket 去实现我们的自定义封装。其中mqtt 和 xmpp 为聊天协议,是最上层的协议,而websocket是传输通讯协议,它是基于socket封装的一个协议。而上面所说的qq-im的私有协议,就是基于 websocket或者 socket 原生进行封装的一个聊天协议。协议优劣对比总之, ios 端要做一个真正的im 产品,一般都是基于socket 或 websocket等,在之上加上一些私有协议来保证的。三、实现一个简单的im1。socket概述socket 其实并不是一个协议,s

5、ocket通常也称作”套接字”,是对tcp/ip 或者udp/ip 协议封装的一组编程接口,用于描述ip 地址和端口,使用socket 实现进程之间的通信(跨网络的)。它工作在 osi 模型会话层(第5 层), socket 是对 tcp/ip等更底层协议封装的一个抽象层,是一个调用接口(api) 。网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个socket ,一个socket 由一个 ip 地址和一个端口号唯一确定。网络架构先看下基于c 的 bsd socket提供的接口:/socket 创建并初始化socket,返回该socket 的文件描述符,如果描述符

6、为 -1 表示创建失败。intsocket(int addressfamily, int type,int protocol)/关闭 socket连接intclose(int socketfiledescriptor)/将 socket 与特定主机地址与端口号绑定,成功绑定返回0,失败返回 -1。intbind (int socketfiledescriptor,sockaddr *addresstobind, int addressstructlength)/接受客户端连接请求并将客户端的网络地址信息保存到 clientaddress 中。intaccept(int socketfilede

7、scriptor,sockaddr *clientaddress, int clientaddressstructlength)/客户端向特定网络地址的服务器发送连接请求,连接成功返回0,失败返回 -1。intconnect(int socketfiledescriptor,sockaddr *serveraddress, int serveraddresslength)/使用 dns 查找特定主机名字对应的 ip 地址。如果找不到对应的 ip 地址则返回 null 。hostent* gethostbyname(char *hostname)/通过 socket 发送数据,发送成功返回成功发

8、送的字节数,否则返回 -1。intsend(int socketfiledescriptor, char *buffer, int bufferlength, int flags)/从 socket 中读取数据,读取成功返回成功读取的字节数,否则返回 -1。int receive(int socketfiledescriptor,char *buffer, int bufferlength, int flags)/通过udp socket 发送数据到特定的网络地址,发送成功返回成功发送的字节数,否则返回 -1。int sendto(int socketfiledescriptor,char *

9、buffer, int bufferlength, int flags, sockaddr *destinationaddress, int destinationaddresslength)/从 udp socket 中读取数据,并保存发送者的网络地址信息,读取成功返回成功读取的字节数,否则返回 -1 。int recvfrom( int socketfiledescriptor,char *buffer, int bufferlength, int flags, sockaddr *fromaddress, int *fromaddresslength)我们用基于os 底层的原生socke

10、t 来实现一个简单的im 。socket 扩展阅读https:/ im 服务端服务端需要做的工作简单的总结下:1.服务器调用socket(.) 创建 socket;2.绑定 ip 地址、端口等信息到socket上,用函数bind(); 3.服务器调用listen(.) 设置缓冲区;4.服务器通过accept(.)接受客户端请求建立连接;5.服务器与客户端建立连接之后,通过send(.)/receive(.) 向客户端发送或从客户端接收数据;6.服务器调用close 关闭 socket;服务端可以电脑或手机等终端,也可以用多种语言c/c+/java/js等去实现后台,当然 oc 也可以实现。这里

11、我们借用node.js实现了一个服务端,来验证socket 效果。需要在 mac 上安装 node 解释器, node 下载,直接下载安装即可,也可以终端命令安装 node 。开启服务器:1.打开终端2.cd到目录 服务端 (node.js)3.nodeserver.js #开启 im 服务器3、实现 im 客户端im 客户端需要做如下4 件事 :1.客户端调用socket(.) 创建 socket;2.绑定 ip 地址、端口等信息到socket上,用函数bind();3.客户端调用connect(.) 向服务器发起连接请求以建立连接;4.客户端与服务器建立连接之后,就可以通过send(.)/

12、receive(.) 向客户端发送或从客户端接收数据;5.客户端调用close 关闭 socket;代码实现我们采用 cocoaasyncsocket框架,封装一个名为wyksocketmanager的单例,来对 socket 相关方法进行调用:为了 demo演示方便,代码中使用的时间都较短,实际开发中根据需要设置#import wyksocketmanager.h#import gcdasyncsocket.h / for tcpstaticnsstring *khost = ;static uint16_t kport = 6969;staticnsinteger kp

13、ingpongouttime = 3;staticnsinteger kpingponginterval = 5;interfacewyksocketmanager ()property (nonatomic, strong) gcdasyncsocket *gcdsocket;property (nonatomic, assign) nstimeinterval reconnecttime;property (nonatomic, assign) nstimeinterval heartbeatsecond;property (nonatomic, strong) nstimer *hear

14、tbeattimer;property (nonatomic, assign) bool socketofflinebyuser; /!= 5) return; _weak _typeof(self) weakself = self; dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(self.reconnecttime * nsec_per_sec), dispatch_get_main_queue(), _strongtypeof(weakself) strongself = weakself;if (strongself.

15、delegate & strongself.delegate respondstoselector: selector(showmessage:) nsstring *msg = nsstring stringwithformat: 断开重连中, %f ,strongself.reconnecttime; strongself.delegate showmessage:msg; strongself.gcdsocket = nil ; strongself initsocket; strongself autoconnect; );/重连时间增长if (self.reconnectti

16、me = 0) self.reconnecttime = 1; else self.reconnecttime += 2; /初始化心跳- (void)initheartbeat self destoryheartbeat;/ 每隔 5s像服务器发送心跳包self.connecttimer = nstimer scheduledtimerwithtimeinterval:5 target: self selector:selector(longconnecttosocket) userinfo: nil repeats:yes;/ 在 longconnecttosocket 方法中进行长连接需

17、要向服务器发送的讯息 self.connecttimer fire;/ 心跳连接-(void)longconnecttosocket/ 根据服务器要求发送固定格式的数据,但是一般不会是这么简单的指令 self sendmsg:心跳连接 ;/取消心跳- (void)destoryheartbeatif (self.heartbeattimer & self.heartbeattimer isvalid) self.heartbeattimer invalidate;self.heartbeattimer = nil ; end我们发了一条消息,服务端成功的接收到了消息后,把该消息再发送回

18、客户端,绕了一圈客户端又收到了这条消息。至此我们用os 底层 socket 实现了简单的im 。这里仅仅是实现了socket 的连接并传输字符串,我们要做的远不止于此。3、四个重要的功能:心跳机制、pingpong机制、断线重连、消息可达(1) 心跳机制心跳机制是相对时间内主动向服务器发送心跳包消息,用来检测tcp 连接的双方是否可用。 tcp 的 keepalive机制只能保证连接的存在,但是并不能保证客户端以及服务端的可用性。真正需要心跳机制的原因其实主要是在于国内运营商的网络地址转换设备超时,对于家用路由器来说 , 使用的是网络地址端口转换(napt), 它不仅改 ip, 还修改 tcp

19、 和udp 协议的端口号 , 这样就能让内网中的设备共用同一个外网ip,造成连接存在,但并不一定可用。而国内的运营商一般nat 超时的时间为5 分钟,频繁心跳会带来耗电和耗流量的弊端,所以通常im 心跳设置的时间间隔为3-5 分钟,甚至10 分钟都行。(2)pingpong机制心跳机制是不能完全保证消息的即时性的,业内的解决方案是辅助采用双向的pingpong机制。pingpong机制当服务端发出一个ping ,客户端没有在约定的时间内返回响应的ack ,则认为客户端已经不在线,这时我们server 端会主动断开socket 连接,并且改由apns 推送的方式发送消息。同样的是,当客户端去发送

20、一个消息,因为我们迟迟无法收到服务端的响应ack 包,则表明客户端或者服务端已不在线,我们也会显示消息发送失败,并且断开socket 连接。(3) 重连机制理论上,自己主动断开的socket 连接(如退出账号,app 退出到后台等),不需要重连。其他的连接断开,我们都需要进行断线重连。一般解决方案是尝试重连几次,如果仍旧无法重连成功,那么不再进行重连。(4) 消息可达(即qos 机制)在移动网络下,丢包、网络重连等情况非常之多,为了保证消息的可达,一般需要做消息回执和重发机制。一般有三种类型:qos(0), 最多发送一次:如果消息没有发送过去,那么就直接丢失。qos(1), 至少发送一次:保证

21、消息一定发送过去,但是发几次不确定。qos(2), 精确只发送一次:它内部会有一个很复杂的发送机制,确保消息送到,而且只发送一次。参考易信,每条消息会最多会有3 次重发,超时时间为15 秒,同时在发送之前会检测当前连接状态,如果当前连接并没有正确建立,缓存消息且定时检查(每隔 2 秒检查一次,检查15 次)。所以一条消息在最差的情况下会有2 分钟左右的重试时间,以保证消息的可达。因为重发的存在,接受端偶尔会收到重复消息,这种情况下就需要接收端进行去重。通用的做法是每条消息都戴上自己唯一的message id(一般是 uuid) 。4、im 的其他实现方式(1) 基于 websocket最具代表

22、性的一个第三方框架socketrocket实现的思路和基于cocoaasyncsocket框架类似,需要编写遵守websocket协议的服务端,感兴趣的也可以参照实现一下。(2) 基于 mqtt协议的框架 -mqttkitmqtt 是一个聊天协议,它比websocket更上层,属于应用层,它的基本模式是简单的发布订阅,也就是说当一条消息发出去的时候,谁订阅了谁就会收到消息。其实它并不适合im 的场景,例如用来实现有些简单im 场景,却需要很大量的、复杂的处理。这个框架是c 来写的,把一些方法公开在mqttkit类中,对外用oc 来调用,这个库有 4 年没有更新了。(3) 基于 xmpp 协议的

23、框架 -mqttkitxmpp 是较早的聊天协议(2000 年发布第一个公开版本),当时主要是用来打通icq、msn 等 pc 端的聊天软件而设计的,技术比较成熟,它本身有很多优点,如开放、标准、可扩展,并且客户端和服务器端都有很多开源的实现,但是相对于移动端它也有很明显的缺点,譬如数据负载过重、不支持二进制,在交互中有50% 以上的流量是协议本身消耗的,需要做深度的二次开发。三、关于 im 通信协议的选择1、序列化与反序列化移动互联网相对于有线网络最大特点是:带宽低,延迟高,丢包率高和稳定性差,流量费用高。所以在私有协议的序列化上一般使用二进制协议,而不是文本协议。常见的二进制序列化库有pr

24、otocol buffers和 messagepack,当然你也可以自己实现自己的二进制协议序列化和反序列的过程,比如蘑菇街的teamtalk 。但是前面二者无论是可拓展性还是可读性都完爆teamtalk(teamtalk连 variant都不支持,一个 int 传输时固定占用4 个字节 ),所以大部分情况下还是不推荐自己去实现二进制协议的序列化和反序列化过程。一条消息数据用protobuf序列化后的大小是 json 的 1/10 、xml 格式的 1/20 、是二进制序列化的1/10 。同 xml 相比, protobuf 性能优势明显。它以高效的二进制方式存储,比 xml 小 3 到 10

25、 倍,快 20 到 100 倍。同时心跳包协议对im 的电量和流量影响很大,对心跳包协议上进行了极简设计:仅 1 byte 。protocolbuffer可能会造成 app 的包体积增大,通过 google 提供的脚本生成的model ,会非常“庞大”,model 一多,包体积也就会跟着变大。如何测试验证 protobuf 的高性能?对数据分别操作100 次, 1000 次,10000 次和 100000 次进行了测试,纵坐标是完成时间,单位是毫秒序列化反序列化xml,json,hessian,protocol buffers序列化对比选择传输格式的时候:protocolbuffer json xmlprotocolbuffer for objective-c 运行环境配置及使用ios 之 protocolbuffer搭建和示例demo2、协议格式设计基于 tcp 的应

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论