[Android]Okhttp心跳策略研究
2019-03-13 本文已影响52人
CangWang
Android组件化架构
心跳pingpong机制
我是苍王,以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。
[Android]如何做一个崩溃率少于千分之三噶应用app--章节列表
这一张非常经典的心跳策略图示
心跳pingpong机制
现在一般的心跳策略,都是从客户端发送一个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送达率是非常高的,如果是最推国外平台,直接依靠推送也非常可靠。