web_socket icon indicating copy to clipboard operation
web_socket copied to clipboard

Connection status is not updating

Open imijanur opened this issue 1 year ago • 2 comments

Describe the bug I am trying to detect the connection status, but it always returning SocketStatus.connected after disconnecting the internet i am not getting any value, I am also unable to detect the reconnection status.

In my app I need to send some signal from the app right after websocket connection. as it streams some data on the screen, i need to resolve any connection breach.

I have also tried to get the status using a timer, it also giving the same value. SocketStatus.connected its unable to detect the connection status.

To Reproduce Steps to reproduce the behavior:

I have use these code to check the status

    _checkWebsocketConnection() async {
        Timer.periodic(Duration(seconds: 3), (timer) async {
          print(socket?.socketHandlerState.status);
        });
      }

Expected behavior It should return SocketConnection.disconnected when internet is disconnected

imijanur avatar May 07 '24 12:05 imijanur

Hi @imijanur , have you set up ping-pong messages between server and client? Sometimes I got the same problem with hung status from platform webSocket (the one that DART provides me for the library), so using ping-pong messages help solving this issue. By default ping message is simple "ping" text message to server and server should respond with either "ping" or "pong". You can run this code example (taken from https://pub.dev/packages/websocket_universal ) and see what is printed in console:

import 'package:websocket_universal/websocket_universal.dart';

/// Example works with Postman Echo server
void main() async {
  /// 1. Create webSocket handler:
  final textSocketHandler = IWebSocketHandler<String, String>.createClient(
    'wss://ws.postman-echo.com/raw', // Postman echo ws server
    SocketSimpleTextProcessor(),
  );

  /// 2. Listen to webSocket messages:
  textSocketHandler.incomingMessagesStream.listen((inMsg) {
    print('> webSocket  got text message from server: "$inMsg" '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });
  textSocketHandler.outgoingMessagesStream.listen((inMsg) {
    print('> webSocket sent text message to   server: "$inMsg" '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });

  /// 3. Connect & send message:
  await textSocketHandler.connect();
  textSocketHandler.sendMessage('Hello server!');
  await Future<void>.delayed(const Duration(seconds: 4));

  // 4. Disconnect & close connection:
  await textSocketHandler.disconnect('manual disconnect');
  textSocketHandler.close();
}

So how this will help? If client is sending "ping" message to server and server does not respond (because there is no internet connection) - then client will be disconnected and show SocketConnection.disconnected status. Also it might be still connected if you have no internet but your server is in local network. Let me know if you have any questions left, later I will update my library to use latest platfrom-level library that Dart team provides https://pub.dev/packages/web_socket_channel .

dvmatyun avatar May 16 '24 12:05 dvmatyun

Also for custom ping/pong messages you can use this example:

import 'package:websocket_universal/websocket_universal.dart';

/// Example for custom Ping/Pong messages
/// IMessageProcessor that sends to and
/// receives simple [String] text from Server
class SocketCustomPingTextProcessor
    implements IMessageProcessor<String, String> {
  @override
  String? deserializeMessage(Object? data) {
    /// Here you can deserialize messages from server as you want it
    /// (so you can do something even with binary data)
    /// (see generic types and other examples for that)
    if (data is String) {
      return data;
    }
    return null;
  }

  /// !!! Here you define whether server response is Pong message
  /// (return true if [data] is PONG message from server)
  @override
  bool isPongMessageReceived(Object? data) {
    if (data is! String) {
      return false;
    }

    /// Echo server responds with same message, so here we consider both:
    /// '{"rpc":"custom_ping"}' and
    /// '{"rpc":"custom_pong"}' as PONG messages
    if (['{"rpc":"custom_pong"}', '{"rpc":"custom_ping"}'].contains(data)) {
      // Do not use 'print' in release version:
      // ignore: avoid_print
      print('> Message $data is PONG message received now!');
      return true;
    }
    return false;
  }

  /// !!! Here you define ping message (as object, can be even binary data)
  @override
  Object get pingServerMessage => '{"rpc":"custom_ping"}';

  /// Here you can serialize message as you wish
  /// For other type of message see generic type and other examples
  @override
  Object serializeMessage(String message) => message;
}

/// Example works with Postman Echo server
void main() async {
  /// Postman echo ws server (you can use your own server URI)
  /// 'wss://ws.postman-echo.com/raw'
  /// For local server it could look like 'ws://127.0.0.1:42627/websocket'
  const websocketConnectionUri = 'wss://ws.postman-echo.com/raw';
  const textMessageToServer = 'Hello server!';
  const connectionOptions = SocketConnectionOptions(
    pingIntervalMs: 1500, // send Ping message every 1500 ms
    timeoutConnectionMs: 4000, // connection fail timeout after 4000 ms
    /// see ping/pong messages in [logEventStream] stream
    skipPingMessages: false,
  );

  /// Example with simple text messages exchanges with server
  /// (not recommended for applications)
  /// [<String, String>] generic types mean that we receive [String] messages
  /// after deserialization and send [String] messages to server.
  final IMessageProcessor<String, String> textSocketProcessor =
      SocketCustomPingTextProcessor();
  final textSocketHandler = IWebSocketHandler<String, String>.createClient(
    websocketConnectionUri, // Postman echo ws server
    textSocketProcessor,
    connectionOptions: connectionOptions,
  );

  // Listening to webSocket status changes
  textSocketHandler.socketHandlerStateStream.listen((stateEvent) {
    // ignore: avoid_print
    print('> status changed to ${stateEvent.status}');
  });

  // Listening to server responses: (here pong messages are NOT shown)
  textSocketHandler.incomingMessagesStream.listen((inMsg) {
    // ignore: avoid_print
    print('> webSocket  got text message from server: "$inMsg" '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });

  // Listening to outgoing messages: (here ping messages are NOT shown)
  textSocketHandler.outgoingMessagesStream.listen((inMsg) {
    // ignore: avoid_print
    print('> webSocket sent text message to   server: "$inMsg" '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });

  textSocketHandler.logEventStream
      .where(
    (e) => {SocketLogEventType.ping, SocketLogEventType.pong}
        .contains(e.socketLogEventType),
  )
      .listen((e) {
    // ignore: avoid_print
    print('> webSocket [type:${e.socketLogEventType.name}] '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });

  // Connecting to server:
  final isTextSocketConnected = await textSocketHandler.connect();
  if (!isTextSocketConnected) {
    // ignore: avoid_print
    print('Connection to [$websocketConnectionUri] failed for some reason!');
    return;
  }

  textSocketHandler.sendMessage(textMessageToServer);

  await Future<void>.delayed(const Duration(seconds: 5));
  // Disconnecting from server:
  await textSocketHandler.disconnect('manual disconnect');
  // Disposing webSocket:
  textSocketHandler.close();
}

dvmatyun avatar May 16 '24 13:05 dvmatyun

closed to no activity

dvmatyun avatar May 29 '24 12:05 dvmatyun