Connection status is not updating
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
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 .
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();
}
closed to no activity