开源一个自用的Android IM库,基于Netty+TCP+Protobuf实现(2)
封装
为什么需要封装呢?说白了,就是为了解耦,为了方便日后切换到不同框架实现,而无需到处修改调用的地方。举个栗子,比如Android早期比较流行的图片加载框架是Universal ImageLoader,后期因为某些原因,原作者停止了维护该项目,目前比较流行的图片加载框架是Picasso或Glide,因为图片加载功能可能调用的地方非常多,如果不作一些封装,早期使用了Universal ImageLoader的话,现在需要切换到Glide,那改动量将非常非常大,而且还很有可能会有遗漏,风险度非常高。
那么,有什么解决方案呢?
很简单,我们可以用工厂设计模式进行一些封装,工厂模式有三种:简单工厂模式、抽象工厂模式、工厂方法模式。在这里,我采用工厂方法模式进行封装,具体区别,可以参见:通俗讲讲我对简单工厂、工厂方法、抽象工厂三种设计模式的理解
我们分析一下,ims(IM Service,下文简称ims)应该是有初始化、建立连接、重连、关闭连接、释放资源、判断长连接是否关闭、发送消息等功能,基于上述分析,我们可以进行一个接口抽象:
OnEventListener是与应用层交互的listener:
IMConnectStatusCallback是ims连接状态回调监听器:
然后写一个Netty tcp实现类:
接下来,写一个工厂方法:
封装部分到此结束,接下来,就是实现了。
初始化
我们先实现init(Vector serverUrlList, OnEventListener listener, IMSConnectStatusCallback callback)方法,初始化一些参数,以及进行第一次连接等:
其中,MsgDispatcher是消息转发器,负责将接收到的消息转发到应用层:
ExecutorServiceFactory是线程池工厂,负责调度重连及心跳线程:
连接及重连
resetConnect()方法作为连接的起点,首次连接以及重连逻辑,都是在resetConnect()方法进行逻辑处理,我们来瞄一眼:
可以看到,非首次进行连接,也就是连接一个周期失败后,进行重连时,会先让线程休眠一段时间,因为这个时候也许网络状况不太好,接着,判断ims是否已关闭或者是否正在进行重连操作,由于重连操作是在子线程执行,为了避免重复重连,需要进行一些并发处理。开始重连任务后,分四个步骤执行:
- 改变重连状态标识
- 回调连接状态到应用层
- 关闭之前打开的连接channel
- 利用线程池执行一个新的重连任务
ResetConnectRunnable是重连任务,核心的重连逻辑都放到这里执行:
toServer()是真正连接服务器的地方:
initBootstrap()是初始化Netty Bootstrap:
注:NioEventLoopGroup线程数设置为4,可以满足QPS是一百多万的情况了,至于应用如果需要承受上千万上亿流量的,需要另外调整线程数。参考自:netty实战之百万级流量NioEventLoopGroup线程数配置
接着,我们来看看TCPChannelInitializerHanlder:
其中,ProtobufEncoder和ProtobufDecoder是添加对protobuf的支持,LoginAuthRespHandler是接收到服务端握手认证消息响应的处理handler,HeartbeatRespHandler是接收到服务端心跳消息响应的处理handler,TCPReadHandler是接收到服务端其它消息后的处理handler,先不去管,我们重点来分析下LengthFieldPrepender和LengthFieldBasedFrameDecoder,这就需要引申到TCP的拆包与粘包啦。
作者:FreddyChen
链接:https://juejin.cn/post/6844903815846559757
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。