「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
netty源码角度看服务器断开连接问题
前文
本文为之前讨论到当网络非常慢时,服务器会主动断开连接。因此从源码角度对该问题进行探索。
相关源码解析
首先需要看一下配置文件,发现其中有pingTimeout以及pingInterval两个参数。根据经验该参数为断开连接的时间设置。因此从源码中继续查找相关引用,找到如下的代码:
public void schedulePingTimeout() {
SchedulerKey key = new SchedulerKey(Type.PING_TIMEOUT, sessionId);
disconnectScheduler.schedule(key, new Runnable() {
@Override
public void run() {
ClientHead client = clientsBox.get(sessionId);
if (client != null) {
client.disconnect();
log.debug("{} removed due to ping timeout", sessionId);
}
}
}, configuration.getPingTimeout() + configuration.getPingInterval(), TimeUnit.MILLISECONDS);
}
如上代码分析可以知道,此处进行了定时任务的指定。每次对该方法进行调用时,都会指定一个定时任务,在60+25也就是85秒后,执行socket连接断开的操作。因此找到了断开的源头,下一步只需要找到什么时间该方法被调用即可。继续查看源码,看到了如下的两部分:
如图可知,第一部分为认证后会进行调用,第二部分大概是消息处理时。认证时也就是第一次连接我们都可以理解,重点来看一下第二部分:
case PING: {
client.getBaseClient().schedulePingTimeout();
}
case UPGRADE: {
client.getBaseClient().schedulePingTimeout();
}
case MESSAGE: {
client.getBaseClient().schedulePingTimeout();
}
case CLOSE:
client.getBaseClient().onChannelDisconnect();
break;
如上所示,代码部分进行了部分简化,仅保留了核心内容。当服务器收到客户端的消息、心跳消息、关闭消息、连接升级等消息时,会调用该方法进行连接断开的定时任务。而当收到消息时,也就会将前一个定时任务进行移除操作,这部分此处暂时忽略。所以当连接后,如果客户端没有向服务器发送消息,则需要在85秒内向服务器发送心跳消息,否则连接将断开。
如上图所示,当客户端消息超过85秒未发送时,产生了服务器连接断开现象。也就解释了当网速比较慢时,客户端消息可能无法成功发送到服务器上,也就是可能导致连接断开问题。
后记
- 千古兴亡多少事?悠悠。不尽长江滚滚流。