首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >flutter websockets自动重新连接-如何实现

flutter websockets自动重新连接-如何实现
EN

Stack Overflow用户
提问于 2019-04-04 03:40:11
回答 3查看 9.4K关注 0票数 12

我正在努力解决如何在flutter中实现websockets自动重新连接。我使用web_socket_channel,然而,插件只包装了dart.io WebSocket,因此任何基于WebSocket类的解决方案也适用于我。

我已经想好了,如何捕捉套接字断开,请看下面的代码片段:

代码语言:javascript
运行
复制
    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,依此类推。

任何帮助都将不胜感激!

EN

回答 3

Stack Overflow用户

发布于 2020-05-30 06:31:50

对于package:web_socket_channel (IOWebSocketChannel),没有任何方法可以实现套接字连接的重新连接。但是您可以使用WebSocket类来实现可重新连接的连接。

您可以使用StreamController类实现WebSocket通道,然后广播消息。工作示例:

代码语言:javascript
运行
复制
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发送的数据

代码语言:javascript
运行
复制
var _streamController = new NotificationController().streamController;

_streamController.stream.listen(pushNotifications);
票数 14
EN

Stack Overflow用户

发布于 2020-05-20 05:28:44

下面是我要做的:

代码语言:javascript
运行
复制
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参数会在出现任何错误时触发套接字关闭。

代码语言:javascript
运行
复制
  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);
  }
票数 1
EN

Stack Overflow用户

发布于 2020-07-14 02:42:10

大多数时候,当我们创建一个WebSocketChannel时,我们将使用它的stream来接收消息,使用sink来发送消息。

重新连接的想法是,当错误发生或套接字关闭时,我们将创建一个新的WebSocketChannel实例,并将其分配到全局共享变量中。但困难的是,在其他地方使用它的stream & sink将是无效的。

为了克服这个问题,我们将创建一个固定的stream & sink来使用新WebSocketChannel实例的等效实例来转发和传输消息。

代码语言:javascript
运行
复制
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);
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55503083

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档