我正在努力解决如何在flutter中实现websockets
自动重新连接。我使用web_socket_channel,然而,插件只包装了dart.io WebSocket,因此任何基于WebSocket
类的解决方案也适用于我。
我已经想好了,如何捕捉套接字断开,请看下面的代码片段:
try {
_channel = IOWebSocketChannel.connect(
wsUrl,
);
///
/// Start listening to new notifications / messages
///
_channel.stream.listen(
_onMessageFromServer,
onDone: () {
debugPrint('ws channel closed');
},
onError: (error) {
debugPrint('ws error $error');
},
);
} catch (e) {
///
/// General error handling
/// TODO handle connection failure
///
debugPrint('Connection exception $e');
}
我想从onDone
内部调用IOWebSocketChannel.connect
,然而,这导致了一种无限循环-因为我必须在再次调用connect
之前关闭_channel
,这反过来又会再次调用onDone
,依此类推。
任何帮助都将不胜感激!
发布于 2020-05-30 06:31:50
对于package:web_socket_channel (IOWebSocketChannel),没有任何方法可以实现套接字连接的重新连接。但是您可以使用WebSocket类来实现可重新连接的连接。
您可以使用StreamController类实现WebSocket通道,然后广播消息。工作示例:
import 'dart:async';
import 'dart:io';
class NotificationController {
static final NotificationController _singleton = new NotificationController._internal();
StreamController<String> streamController = new StreamController.broadcast(sync: true);
String wsUrl = 'ws://YOUR_WEBSERVICE_URL';
WebSocket channel;
factory NotificationController() {
return _singleton;
}
NotificationController._internal() {
initWebSocketConnection();
}
initWebSocketConnection() async {
print("conecting...");
this.channel = await connectWs();
print("socket connection initializied");
this.channel.done.then((dynamic _) => _onDisconnected());
broadcastNotifications();
}
broadcastNotifications() {
this.channel.listen((streamData) {
streamController.add(streamData);
}, onDone: () {
print("conecting aborted");
initWebSocketConnection();
}, onError: (e) {
print('Server error: $e');
initWebSocketConnection();
});
}
connectWs() async{
try {
return await WebSocket.connect(wsUrl);
} catch (e) {
print("Error! can not connect WS connectWs " + e.toString());
await Future.delayed(Duration(milliseconds: 10000));
return await connectWs();
}
}
void _onDisconnected() {
initWebSocketConnection();
}
}
因为通知控制器返回一个单例实例,所以在服务器和设备之间总是有一个套接字连接。利用StreamController的广播方式,可以在多个用户之间共享通过Websocket发送的数据
var _streamController = new NotificationController().streamController;
_streamController.stream.listen(pushNotifications);
发布于 2020-05-20 05:28:44
下面是我要做的:
void reconnect() {
setState(() {
_channel = IOWebSocketChannel.connect(wsUrl);
});
_channel.stream.listen((data) => processMessage(data), onDone: reconnect);
}
然后,要启动websocket,只需执行一次初始调用reconnect()。基本上,这样做是在调用onDone回调时重新创建WebSocket,这在连接被破坏时发生。所以,连接被破坏了--好的,让我们自动重新连接。我还没有找到不重新创建_channel就能做到这一点的方法。例如,理想情况下,应该有一个_channel.connect()可以重新连接到现有的URL,或者某种自动重新连接功能,但这似乎并不存在。
哦,这里有一个更好的东西,它可以在远程服务器关闭时消除丑陋的重新连接异常回溯,并添加4秒的重新连接延迟。在这种情况下,cancelOnError参数会在出现任何错误时触发套接字关闭。
wserror(err) async {
print(new DateTime.now().toString() + " Connection error: $err");
await reconnect();
}
reconnect() async {
if (_channel != null) {
// add in a reconnect delay
await Future.delayed(Duration(seconds: 4));
}
setState(() {
print(new DateTime.now().toString() + " Starting connection attempt...");
_channel = IOWebSocketChannel.connect(wsUrl);
print(new DateTime.now().toString() + " Connection attempt completed.");
});
_channel.stream.listen((data) => processMessage(data), onDone: reconnect, onError: wserror, cancelOnError: true);
}
发布于 2020-07-14 02:42:10
大多数时候,当我们创建一个WebSocketChannel
时,我们将使用它的stream
来接收消息,使用sink
来发送消息。
重新连接的想法是,当错误发生或套接字关闭时,我们将创建一个新的WebSocketChannel
实例,并将其分配到全局共享变量中。但困难的是,在其他地方使用它的stream
& sink
将是无效的。
为了克服这个问题,我们将创建一个固定的stream
& sink
来使用新WebSocketChannel
实例的等效实例来转发和传输消息。
class AutoReconnectWebSocket {
final Uri _endpoint;
final int delay;
final StreamController<dynamic> _recipientCtrl = StreamController<dynamic>();
final StreamController<dynamic> _sentCtrl = StreamController<dynamic>();
WebSocketChannel? webSocketChannel;
get stream => _recipientCtrl.stream;
get sink => _sentCtrl.sink;
AutoReconnectWebSocket(this._endpoint, {this.delay = 5}) {
_sentCtrl.stream.listen((event) {
webSocketChannel!.sink.add(event);
});
_connect();
}
void _connect() {
webSocketChannel = WebSocketChannel.connect(_endpoint);
webSocketChannel!.stream.listen((event) {
_recipientCtrl.add(event);
}, onError: (e) async {
_recipientCtrl.addError(e);
await Future.delayed(Duration(seconds: delay));
_connect();
}, onDone: () async {
await Future.delayed(Duration(seconds: delay));
_connect();
}, cancelOnError: true);
}
}
https://stackoverflow.com/questions/55503083
复制相似问题