一、开发IM的同学建议空暇时间多去(即时通讯)官网看看相关资料,便于自己能更好的优化自己的逻辑
二、通篇文章在 https://blog.csdn.net/weixin_43487250/article/details/123767010 有书面详细形式总结
三、下方总结是IM选型从那些方面考虑和调研(备注:下方涉及到的项目和demo等可以联系楼主索要demo或者项目源码)
自研发IM /继承第三方研发IM整套架构设计
1.第三方形式,根据app业务,是否设计国内外以及不同的收费标准主流有七牛云,阿里百川,腾讯云,网易,融云,环信等多家主流三方,个人倾向网易和融云。
原因:
网易比较快速集成,各网站资料较多,容易借鉴。但后续带宽服务收费较高。
融云也容易集成,但是SDK自带UI和不带UI的是两套SDK,初始化方法差异性较大,但是融云的性能较好,对消息本息存储做API的比较容易理解和调用
1.网易IM在(有完整项目)项目有完整体现,包含了视频会议,群聊,群视频音频通话,阅后即焚,单聊,且支持所有聊天消息类型,图文,语音,文本,视频,群公告,群链接等
2.融云在(有完整项目)项目有体现,具体包含了聊天室功能,用以直播间的实时评论
以上两种用法暂不阐述,可以再具体项目中学习以及可以参照官方开发文档进行开发,但是其中的性能优化等整体优化方案需由开发者自行设计,学自研发IM的同学可以多下载第三方的demo,参照其整体架构模式设计有很好的的帮助
下面着重讲一下自研发IM的方式
1.首先自研发IM,要对socket有一定的了解,毕竟IM是基于长连接的实现方式。
2.完成所有API设计后打包成SDK供上层开发同学使用,这里涉及到的SDK的设计思路和打包方法后续楼主其他文章可以查阅。
1.socket的选型有socket,websocket,对两种方式要有所了解
套接字(Socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。
ok,看到这里还有蒙圈的同学,大抵是对网络的七层协议理解的有所遗忘,所以回过头需要把网络的七层协议都了解一下方便知道每一层是如何工作的
OSI的7层从上到下分别是7应用层6表示层5会话层4传输层3网络层2数据链路层1物理层;其中高层(即7、6、5、4层)定义了应用程序的功能,下面3层(即3、2、1层)主要面向通过网络的端到端,点到点的数据流。
参考文档:https://baike.baidu.com/item/网络七层协议/6056879?fr=aladdin,通读文档可以理解,高层是通过底层的接口来实现交互,低层也可以理解为我们ios的api底层,他只需要谁调用他时候,传来参数即可,至于底层的实现协议和算法无需高层考虑,那么低层从高层就很好理解了,电信号,电流等表示物理层,光纤传输链路则为数据链路层,路由则为网络层,而我们的tcp和udp就是传输层了,消息数据的传递就是会话层,数据的处理就是表示层,最后统一到底应用程序,就是应用层了。
而我们需要重点关注的是代码配置方向的层面,物理层,链路层,会话层是不需要我们重点关注的,都是由硬件决定,软件决定的范围只有 应用层+会话层+传输层。
Tcp和UDP区别:
https://www.xinnet.com/xinzhi/65/118739.html
选型参考:
http://www.52im.net/thread-33-1-1.html https://blog.csdn.net/qq_21521371/article/details/81199071 https://zhidao.baidu.com/question/563196162991295124.html
通过以上文章分析,目前我们采用TCP协议进行传输
可以揣测到微信是基于TCP的链接,部分采用UDP传输,部分采用TCP传输应该
3.下面就开始我们的套接字的选型了,套接字分为Socket和websocket,二者的区别
参考:https://blog.csdn.net/qushaming/article/details/90747326
https://www.cnblogs.com/barrywxx/p/7412808.html
webSocket是基于http短连接,轮询,长轮询之后诞生的基于http协议的应用层协议的一层协议,其是通过http建立连接,但是也是基于TCP协议传输,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。而socket是基于数据传输层的协议,是虚拟出来的一层,可以理解为传输层和表示层中间的一种接口协议
4.iOS平台有哪些WebSocket和Socket的开源框架
Socket开源框架有:CocoaAsyncSocket,socketio/socket.io-client-swift
WebSocket开源框架有:facebook/SocketRocket,tidwall/SwiftWebSocket
OK到这里 webSocket的底层连接方法
开头的链接中,将这些方法封装在你自己的SDK中,并对数据进行处理,如存储,加密,前后端定义好,并遵循SDK设计原则,将上层对接的同学需要的业务曝露在自己的API里面
5.单机最大的tcp连接数可以参考http://www.52im.net/thread-561-1-1.html,做单机垂直负载扩展的优化,然后在考虑分布负载的水平优化,做到最大限度的服务器优化
socket开发方式:
参考资料:https://www.jianshu.com/p/0a11b2d0f4ae
下面说一下IM自研发/非自研发的整体架构可参考https://codingdict.com/os/software/65233
1.所有点h合集的目标文件(类似PCH)CDChatList
2消息类型API CDChatListProtocols
可以包含任何你想暴露出来的代理方法,属性,枚举
如:
typedef enum : NSUInteger {
CDMessageTypeText, //文字类型0
CDMessageTypeImage, //图片类型1
CDMessageTypeAudio, //音频类型2
CDMessageTypeSystemInfo,//系统信息类型3
CDMessageTypeVIDEO, //视频类型
CDMessageTypeDING, //视频类型
CDMessageTypeLocation, //位置类型
CDMessageTypeFile, //文档类型
CDMessageTypeBig,//点赞大表情
CDMessageTypeCancel,//撤回
CDMessageTypeTouch, // @类型
CDMessageTypeReply, //回复
CDMessageTypeVoiceToText,//语音转文字
CDMessageTypeGroupAnn,//群公告
CDMessageTypeBusinessCard, //名片
CDMessageTypeMeeting, //会议消息
CDMessageTypeVoiceWithVideo,// 语音视频
} CDMessageType;//消息类型
typedef enum : NSUInteger {
CDMessageStateNormal,
CDMessageStateSending, //图片消息上传中/文字消息发送中
CDMessageStateSendFaild, //消息发送失败
CDMessageStateDownloading, //图片消息下载中
CDMessageStateDownloadFaild //图片消息下载失败
} CDMessageState;
3.每一个大的功能既然都有单独的一个单例类来管理,其涉及到的点击事件也要单独放在这个管理类里面,且要用多级代理的方式最终将点击事件的具体实现引入到CDViewController.h层级中
目的:
1.便于管理,修改和维护
2.便于VC之间的交互,跳转,数据传递等
如:CTMoreKeyBoard文件中的点击事件
4.优化点:1.CTTextView文件中 textView设置为不可滚动,防止输入跳动,则其高度根据输入文字以及间距实时监听并计算,修改其高度
5.以前微信一条消息的长按 会有两种方式,1.长按出现复制,转发等弹出框,一边长按一边横向滑动会出现放大镜,
那么 长按 和长按横向拖动 会有两种弹出视图切换,如何检测
currentMode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain());
self.backgroundColor =[UIColor clearColor];
_selectionStartPosition = 5;
_selectionEndPosition = 1;
[self setupGestures];
__weak __typeof(self)weakSelf = self;
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault,kCFRunLoopAllActivities,YES,0,^(CFRunLoopObserverRef observer,CFRunLoopActivity activity){
__strong __typeof(weakSelf)strongSelf = weakSelf;
if(strongSelf==nil){
return;
}
CFComparisonResult rest = CFStringCompare(strongSelf->currentMode,CFRunLoopCopyCurrentMode(CFRunLoopGetMain()),kCFCompareBackwards);
if(rest != kCFCompareEqualTo){
strongSelf->currentMode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain());
if((NSString *)CFBridgingRelease(strongSelf->currentMode)== UITrackingRunLoopMode){
[strongSelf scrollDidScroll];
}
}
});
CFRunLoopAddObserver(CFRunLoopGetMain(),observer,kCFRunLoopCommonModes);
所以可以通过CFRunLoopObserverRef监听,通过UITrackingRunLoopMode对比来处理拖动事件
5.coreText 做IM的图形排版,图文混排的优势
https://www.pianshen.com/article/41191695402/
6.新消息进来时候,更新的是消息列表的数据源,并更新整个tableView的总高,这里更新总高的时候,旧消息的高度是在消息模型中有存储,而新消息的高度计算后并进行存储,新消息的计算方式优化到coreText的排版引擎,并提前将文本内容进行渲染,而新消息的展示则直接在tableView的底部插入最新一行,不需要整体刷新,并且某一条数据若是出现不及时,卡顿时候需要用dispaycell进行预渲染刷新处理。
如何实现安全?
在SDK与服务器的连接建立过程中有一个复杂的秘钥协商过程,首先客户端需要生成一个一次性使用的加密秘钥,并使用非对称加密方式将这个秘钥加密之后传给服务器,加密数据会被服务器解密,之后该加密秘钥被保留在该长连接的会话信息中,数据来往均使用该秘钥加密,这是一个流式加密,可以有效防止中间人攻击和数据包回放等攻击手段。