探究Android Okhttp的心跳策略
我是苍王,以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。 [Android]如何做一个崩溃率少于千分之三噶应用app--章节列表
这一张非常经典的心跳策略图示
现在一般的心跳策略,都是从客户端发送一个ping信号给服务器,告诉服务器是长连接存活。 服务器会返回一个pong信号给客户端,让其更新心跳线程时间。如果超时没有接收到信号,那么客户端考虑重连机制。
这里说一下okhttp有提供了WebSocket的封装,我们的应用也是使用了WebSocket,那就直接看一下WebSocket对pingpong的封装
public Builder() {
……
//这里默认的ping的时间间隔为0,因为okhttp也可以有如http短连接
pingInterval = 0;
}
Builder(OkHttpClient okHttpClient) {
……
//builder函数提供封装
this.pingInterval = okHttpClient.pingInterval;
}
//设置间隔
public Builder pingInterval(long interval, TimeUnit unit) {
pingInterval = checkDuration("interval", interval, unit);
return this;
}
在RealWebSocket中启动循环发送ping信号
public void initReaderAndWriter(String name, Streams streams) throws IOException {
synchronized (this) {
this.streams = streams;
this.writer = new WebSocketWriter(streams.client, streams.sink, random);
this.executor = new ScheduledThreadPoolExecutor(1, Util.threadFactory(name, false));
if (pingIntervalMillis != 0) {
//循环定时任务
executor.scheduleAtFixedRate(
new PingRunnable(), pingIntervalMillis, pingIntervalMillis, MILLISECONDS);
}
if (!messageAndCloseQueue.isEmpty()) {
runWriter(); // Send messages that were enqueued before we were connected.
}
}
reader = new WebSocketReader(streams.client, streams.source, this);
}
private final class PingRunnable implements Runnable {
PingRunnable() {
}
@Override public void run() {
//写入ping信号
writePingFrame();
}
}
void writePingFrame() {
WebSocketWriter writer;
int failedPing;
synchronized (this) {
if (failed) return;
writer = this.writer;
//是否等待pong信号
failedPing = awaitingPong ? sentPingCount : -1;
//等待ping计数
sentPingCount++;
//等待pong
awaitingPong = true;
}
//ping失败,长连接失效
if (failedPing != -1) {
failWebSocket(new SocketTimeoutException("sent ping but didn't receive pong within "
+ pingIntervalMillis + "ms (after " + (failedPing - 1) + " successful ping/pongs)"),
null);
return;
}
try {
//写入空支付到websocket头部
writer.writePing(ByteString.EMPTY);
} catch (IOException e) {
failWebSocket(e, null);
}
}
在RealWebSocket的call中执行loopReader监听读取接收到的信息
/** Receive frames until there are no more. Invoked only by the reader thread. */
public void loopReader() throws IOException {
//监听信息
while (receivedCloseCode == -1) {
// This method call results in one or more onRead* methods being called on this thread.
reader.processNextFrame();
}
}
void processNextFrame() throws IOException {
//读取头部
readHeader();
if (isControlFrame) {
//读取头部信息体
readControlFrame();
} else {
readMessageFrame();
}
}
读取到是顶部信息
private void readControlFrame() throws IOException {
if (frameLength > 0) {
source.readFully(controlFrameBuffer, frameLength);
if (!isClient) {
controlFrameBuffer.readAndWriteUnsafe(maskCursor);
maskCursor.seek(0);
toggleMask(maskCursor, maskKey);
maskCursor.close();
}
}
switch (opcode) {
//读取ping信号
case OPCODE_CONTROL_PING:
frameCallback.onReadPing(controlFrameBuffer.readByteString());
break;
//读取pong信号
case OPCODE_CONTROL_PONG:
frameCallback.onReadPong(controlFrameBuffer.readByteString());
break;
//读取到关闭连接信号
case OPCODE_CONTROL_CLOSE:
int code = CLOSE_NO_STATUS_CODE;
String reason = "";
long bufferSize = controlFrameBuffer.size();
if (bufferSize == 1) {
throw new ProtocolException("Malformed close payload length of 1.");
} else if (bufferSize != 0) {
code = controlFrameBuffer.readShort();
reason = controlFrameBuffer.readUtf8();
String codeExceptionMessage = WebSocketProtocol.closeCodeExceptionMessage(code);
if (codeExceptionMessage != null) throw new ProtocolException(codeExceptionMessage);
}
frameCallback.onReadClose(code, reason);
closed = true;
break;
default:
throw new ProtocolException("Unknown control opcode: " + toHexString(opcode));
}
}
读取到pong信号,等待pong置为false
@Override public synchronized void onReadPong(ByteString buffer) {
// This API doesn't expose pings.
receivedPongCount++;
awaitingPong = false;
}
这就是使用OkHttp的WebSocket keepAlive的流程,而基本的okhttp的socket连接也是通过类似发送这种pingpong信号来维持,之需要设置维护的时间。 然后keepAlive的经验以前的经验值是59秒,微信的大神的方案是通过记录socket连接和断开时间,适配出最适当的发送长链接时间,有兴趣可以自己实验写一个算法。 微信的智能心跳方案
这边做IM的应用的,说一下这边方案,仅供参考。 手机进入后台后十秒后主动关闭长连接,通过推送来维护消息,这里有个问题就是国内的Umeng推送可达率大家懂的,小米和华为还好点,如果是其他山寨机,到8.0后后台很难保活了。如果是国外FCM送达率是非常高的,如果是最推国外平台,直接依靠推送也非常可靠。
上一篇: 理解多路SOCKET心跳包和注册包的功能
下一篇: 微信安卓版智能心跳功能详解
推荐阅读
-
深入探究Android View的requestLayout、invalidate和postInvalidate功能,强烈推荐收藏
-
探究TCP应用为何需要心跳包:TCP Keep-Alive的原理解析
-
探究Android Okhttp的心跳策略
-
安卓系统发送彩信失败,探究 Android 彩信接口的问题
-
搞定!Android笔记:OkHttp解析DNS超时时间设置的困扰
-
聊聊QUIC协议的基本工作原理、性能表现探究以及部署策略解读
-
如何识别网站是否遭遇了K降权?探究网站K降权的起因及应对策略
-
改进Android应用图片加载策略的方法论
-
【2022新手指南】Java编程进阶之路 - 六、技术架构篇 ### MySQL索引底层解析与优化实战 - 你会讲解MySQL索引的数据结构吗?性能调优技巧知多少? - Redis深度揭秘:你知道多少?从基础到哨兵、主从复制全梳理 - Redis持久化及哨兵模式详解,还有集群搭建和Leader选举黑箱打开 - Zookeeper是个啥?特性和应用场景大公开 - ZooKeeper集群搭建攻略及 Leader选举、读写一致性、共享锁实现细节 - 探究ZooKeeper中的Leader选举机制及其在分布式环境中的作用 - Zab协议深入剖析:原理、功能与在Zookeeper中的核心地位 - RabbitMQ全方位解读:工作模式、消费限流、可靠投递与配置策略 - 设计者视角:RabbitMQ过期时间、死信队列与延时队列实践指南 - RocketMQ特性和应用场景揭示:理解其精髓与差异化优势 - Kafka详细介绍:特性及广泛应用于实时数据处理的场景解析 - ElasticSearch实力揭秘:特性概述与作为搜索引擎的广泛应用 - MongoDB认知升级:非关系型数据库的优势阐述,安装与使用实战教学 - BIO/NIO/AIO网络模型对比:掌握它们的区别与在网络编程中的实际应用 - Netty带你飞:理解其超快速度背后的秘密,包括线程模型分析 - 网络通信黑科技:Netty编解码原理与常用编解码器的应用,Protostuff实战演示 - 解密Netty粘包与拆包现象,怎样有效应对这一常见问题 - 自定义Netty心跳检测机制,轻松调整检测间隔时间的艺术 - Dubbo轻骑兵介绍:核心特性概览,服务降级实战与其实现益处 - Dubbo三大神器解读:本地存根与本地伪装的实战运用与优势呈现 ----------------------- 七、结语与回顾
-
探究并实现Android设备的远程调试方法