-
Notifications
You must be signed in to change notification settings - Fork 180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
An Issue with Client Connection in Dart Language 一个非常奇怪的bug #331
Comments
你将客户端的keepalive参数设置长一点,比如2分钟 |
我用的是mqtt5_client,我实际上已经设置了keepAlive,但是这个库的作者说你不用设置这玩意,我现在有点懵逼了,不知道是broker的问题还是client的问题。 |
变现就是本来都已经连上了(实际上我的auth是全部通过),然后从flutter的log来看,是连上了然后又不知道什么原因断开了,原因未知,很奇怪 |
client keepalive is below minimum recommended value and may exhibit connection instability |
Could also be a problem of creating multiple connections using the same client_id / client_name information - this was the an issue in my environment. Suggestions for flutter:
|
你用的什么客户端,将简化代码贴出来我可以看看 |
@werbenhu 非常感谢大佬分析和回答。 我用的是这个库:mqtt5_client. flutter. 这个是我的简化connect代码: @override
Future<bool> connect(
{required host,
required String username,
required String password,
String? clientId,
int? port}) async {
if (!connectLock) {
String cid = clientId ?? getClientId()!;
_clientId = cid;
if (useWebsocket) {
host = "ws://" + host;
}
_client =
// MqttServerClient.withPort(host, cid, 1883, maxConnectionAttempts: 3);
MqttServerClient.withPort("test.mosquitto.org", cid, 1883,
maxConnectionAttempts: 3);
kLog(
'!!!! ------------> [conn] connect with $host, $port, $username, $password, ${_clientId} $_client');
_client!.logging(on: true);
// _client!.logging(on: false);
_client!.onConnected = onConnected;
_client!.onDisconnected = onDisconnected;
_client!.onUnsubscribed = onUnsubscribed;
_client!.onSubscribed = onSubscribed;
_client!.onSubscribeFail = onSubscribeFail;
_client!.onAutoReconnect = onAutoReconnect;
_client!.pongCallback = pong;
_client!.keepAlivePeriod = 60 * 3;
_client!.autoReconnect = false;
_client!.useWebSocket = useWebsocket;
final connMessage = MqttConnectMessage()
.authenticateAs(username, password)
// .withWillTopic('lastwills')
// .withWillMessage('Will message')
.withClientIdentifier(cid);
// .withProtocolName("MQTT")
// .withProtocolVersion(4)
// .withSessionExpiryInterval(interval)
// .withWillQos(MqttQos.atLeastOnce);
_client!.connectionMessage = connMessage;
connectLock = true;
try {
//_messagesController = StreamController.broadcast();
_broadcastConnectionState();
await _client!.connect();
_broadcastConnectionState();
// only after connected?
_subscribeToArchivesTopics();
_listenAndFilter();
connectLock = false;
return true;
} catch (e) {
kLog('Exception: $e');
if (_client != null) _client!.disconnect();
connectLock = false;
return false;
}
} else {
kLog("!!!!xxx connect is locked ! do not repeat connect");
return false;
}
} 不知道大佬能否看懂dart代码,但逻辑上应该差不多。 我目前的问题是两个:
|
用这个 You can use .keepAliveFor(120) to set the keep-alive. The reason for two connections might be that the client's keep-alive setting is too short, causing the server to disconnect the client, and then the client automatically reconnects? final connMessage = MqttConnectMessage()
.authenticateAs(username, password)
.keepAliveFor(120)
.withClientIdentifier(cid);
_client!.connectionMessage = connMessage; |
@werbenhu hi, what's the properly keepalive time for a chating mobile app? using 120 means every 2 miniutes it needs to re-connect if no packet send. Will it consume many battery life? what's this value set to normally ? |
About keep alive, you can refer to MQTT spec 3.1.2.10 Keep Alive. The line |
@OpenJarvisAI Has there been any progress on this issue? Can it be closed now? |
@werbenhu 这个问题至今仍未解决,我现在服务端的log大概是这样:
就是一连接,立马就断开。 @IshanDaga 感觉跟这个用户的现象是一致的。 也就是说,我这边用同样的clientId去创建了连接,但是之前的,服务端并不知道掉线了。 这个就比较蛋疼,客户端好像没有明确的把disconnect信息,传递给服务端。 但这也不能说是客户端的库有问题, 这个问题导致的原因是因为 手机休眠机制。 实际上应用退到后台(不是退出),我估计被系统杀死了,没有一句话发出去。 然后回到前台,由于客户端开启了自动连接,他就自动连接了。但是不管你怎么连接,你的判断都是错的,因为你掉线了,但是服务器并不知道,于是无论如何都要重练,也无论如何都会被服务器 先连接上然后断开。 基于此,想请问各位有什么办法么? |
这个流程有问题吗?没有问题啊!你之前的连接还没有超时(keepalive时间内)服务器将它看成连接还在线,这时候你又来一个连接(同一个客户端ID),服务端要断开之前的连接,然后保存新连接,没问题啊。 OnDisconnect那里可以判断是否是重连的,这个代码就是: // OnDisconnect removes a client from the store if they were using a clean session.
func (h *Hook) OnDisconnect(cl *mqtt.Client, _ error, expire bool) {
if h.db == nil {
h.Log.Error("", "error", storage.ErrDBFileNotOpen)
return
}
if !expire {
return
}
// 如果是重连,不清除数据库里的连接数据
if cl.StopCause() == packets.ErrSessionTakenOver {
return
}
err := h.db.HDel(h.ctx, h.hKey(storage.ClientKey), clientKey(cl)).Err()
if err != nil {
h.Log.Error("failed to delete client", "error", err, "id", clientKey(cl))
}
} |
@OpenJarvisAI 客户端主动关闭连接的服务端是可以马上知道的,因为客户端给服务端发送了一个disconnect或者直接关闭了连接,但是如果客户端是拔网线,关机类似这种情况,服务端只能通过keepalive心跳包来自己判断,你可以随便找一个PC mqtt客户端,连上后拔掉网线,你可以看看服务端是不是 1.5 * keepalive后才会触发disconnect。这些都在mqtt标准协议里面有说到的。 |
@OpenJarvisAI one approach here could be to run your MQTT Client in a flutter isolate (background process), to ensure that it keeps running despite the app being put to sleep by the phone. Some docs are available here. Ofcouse, as @werbenhu suggested, you could also have a very short |
@werbenhu 对的,这个逻辑服务端没有问题。 我思考再三,觉得本质上还是拔网线了(相当于),没有及时告知服务器。 @IshanDaga isolate 之前试过,好像也不行,有可以work的例子吗? 因为整个mqttlclient 有一些数据库的操作,跑isolate代码改动较大。 我尝试一下吧keepAlive 改为1s试一下。 但是这样的话,会不会增加手机功耗 |
我试了一下吧keepAlive 改为 1s 不行, 感觉还是mqtt_client这个client写的有问题,或者是使用有问题。 |
为什么客户端设置了keepAliveFor 1s ,客户端会1s中掉线一次?
有人知道吗 |
@OpenJarvisAI keepalive推荐至少60s以上 |
你看看这个。 |
@werbenhu 大佬,我有点看不懂了,刚才不是说,不如把时间设置成1s吗?我之前就是设置的很大,依旧会有这个问题,刚才设置了1s,也是一样。 迷茫了啊 |
现在问题并不是拔网线,我把数据链接关掉,然后再打开,是不会出现重复连接问题的。 神奇就神奇在这里。但是偶尔退到后台,多一段时间会重复连接 |
我记得我之前帮你查过这个客户端的代码:keepAliveFor(120),这个才是设置keepalive。你按我这个配置来: client!.keepAlivePeriod = 60, 你换成这两个配置试试看。 你要先搞清楚keepalive是干嘛的, keepalive是服务端保存客户端存活时间的,也就是如果keepalive是60秒,服务端如果60秒没有收到客户端的心跳包就认为客户端掉线了,你觉得设置成1秒是合理的吗? |
@werbenhu 我咋感觉这个指标单传给服务器是不合理的,客户端他必然得根据这个值法心跳,不然设置个蛋。 我现在改成了 120,最新代码:
还是一如既往的,推到主屏幕,隔一段时间(超过2min),再打开app,就会一直重复连接。 这次我彻底迷茫了啊。我日了。 我感觉本质原因还是,回来的时候,客户端其实已经断了,被系统杀死了,服务器不知道,而AutoReconnect还是沿用的原来的连接,就肯定被服务器断开,说 用了一个已经断开的连接 我已经在flutter app里面,监控了appLifeCycle,在detach的时候手动的disconnect,无奈,没吊用。 可有破解之法啊 |
_client!.keepAlivePeriod = 60 ,这个就是那个客户端的心跳间隔时间。就是它,我之前稍微看了下那个客户端的代码。你吧这个也带上去。心跳间隔时间最少也应该是一个keepalive。这里设置成60秒,相当于一个keepalive之内,客户端会发送两个心跳。 你可以在服务端加点日志看看,server.go里处理心跳包的地方加个日志看看,看看客户端有没有发送心跳。 // processPingreq processes a Pingreq packet.
func (s *Server) processPingreq(cl *Client, _ packets.Packet) error {
return cl.WritePacket(packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Pingresp, // [MQTT-3.12.4-1]
},
})
} 另外从你的日志来看,服务端似乎没有断开这个连接,而是客户端自己重连导致的,如果心跳还在维持,客户端不应该重新连接才对的。 |
Hello,最近使用 flutter的client,连接服务。用的是mqtt5_client这个lib。
服务端报错:
表现时,一连接上,立马就断开。
现在不知道是客户端还是服务端的问题? 是什么原因导致的呢?
The text was updated successfully, but these errors were encountered: