前言
WebSocket 大家都不陌生了,我们今天来看看怎么在Flutter中使用WebSocket!
开发环境
- Android Studio
- Android SDK API 33
Flutter 安装插件
web_socket_channel: ^2.2.0
正文
我们使用 WebSocket库来进行WebSocket的相关操作
一、连接
使用该库的连接方法为以下方式
IOWebSocketChannel ioWebSocketChannel = IOWebSocketChannel.connect("ws://ip:端口/ws");
连接成功后,我们下一步就是进行监听Socket消息
二、ListenerStream(监听Socket消息)
以下是监听Socket消息方式
ioWebSocketChannel.stream.listen((data){
//消息
}));
值得一提的是监听方式不但可以监听消息,还可以监听异常和Socket连接是否结束
以下是代码示例
ioWebSocketChannel.stream.listen((event) {
},onDone: (){
//结束!
},onError: (){
//异常!
});
我们知道,当Socket服务一定时间内没收到消息则会认为超时,那么我们应该发送心跳包,接下来会逐步介绍
三、SendMessage(发送Socket消息)
发送Socket消息也非常简单,请看代码示例
ioWebSocketChannel.sink.add("消息");
add(T) 可以发送的消息是一个泛型,意味着你可以发送不同的消息至服务器
四、发送心跳包
什么是心跳包呢?简述概括就是:
当Socket服务一定时间没有收到消息则会自动断连,那么此时我们要做的就是一定时间内发送心跳消息至Socket服务,让服务认为客户端还活着,从而继续工作!
我们从中可以得到一些关键字的消息
一定时间发送消息至服务器
第一时间我们想到的就是定时器(Timer) 当然如果你想用Future的延迟也是可以的!
说了那么多,我们看看如何实现!
定义计时器方法
/**
* 发送心跳包
*/
static void sendHeartPacket(){
Map<String,dynamic> data = {
"code": 9999,
"msg": "心跳包",
};
var jsonData = json.encode(data);
IOWebSocketChannel.sink.add(jsonData);
}
我们定义了一个基础的发包方法,那我们接下来需要处理的就是,在一定时间内发心跳包到服务器,如果心跳包发成功了,那么我们应该重新连接
发送心跳包
/**
* @desc WebSocket心跳包
* @author Marinda
* @date 2022/9/26
*/
static void heartPacket(){
//自定义Bool,判断是否Socket开启状态
if(state.socketStatus){
//自定义重连时间间隔
hearTimer = Timer(Duration(seconds: state.socketClienTime),() async{
// 重新连接
reconnectSocket();
});
sendHeartPacket();
}
}
断开连接
/**
* 销毁心跳包
*/
static void destoryHeart(){
//为心跳包则直接
if(state.heartStatus){
hearTimer?.cancel();
state.heartStatus = false;
}
}
重新连接
/**
* 重新连接socket
*/
static void reconnectSocket(){
destoryHeart();
connectSocket();
}
代码示例
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'State.dart';
import 'dart:convert';
import 'Result.dart';
/**
* @date 2022/9/26
* @author Marinda
* @desc websocket的实现
*/
class WebSocketHandle {
static WebSocketState state = WebSocketState();
static late Timer hearTimer;
WebSocketHandle();
static void connectSocket() async {
await closeSocket();
String socketUrl = state.socketUrl;
LoggerUtil.logger.i("发起WebSocket请求,地址为:${socketUrl}");
state.webSocket = IOWebSocketChannel.connect(socketUrl);
state.socketStatus = true;
initConnectSocket();
}
static void initConnectSocket(){
WebSocketHandle.onMessageListener();
heartPacket();
}
/**
* @desc 校验连接配置是否重复
* @author Marinda
* @date 2022/9/27
*/
static bool validConnection(String ip,int port){
return state.ip == ip && state.port == port ? true : false;
}
/**
* @desc WebSocket消息监听器
* @author Marinda
* @date 2022/9/26
*/
static void onMessageListener(){
WebSocketResult webSocketResult = WebSocketResult();
state.webSocket?.stream.listen((data){
var jsonData = json.decode(data);
if(jsonData is Map<String,dynamic>){
//检测到心跳包
if(jsonData['code'] == 9999){
// 不处理
}else{
Map<String,dynamic> mapData = jsonData['data'];
webSocketResult = WebSocketResult.fromJson(mapData);
state.webSocketResult = webSocketResult;
LoggerUtil.logger.i("监听到服务端Socket返回数据: ${state.webSocketResult.toString()}");
},onError: (e){
state.socketStatus = false;
state.isError = true;
},onDone: (){
state.socketStatus = false;
});
}
/**
* 销毁心跳包
*/
static void destoryHeart(){
//为心跳包则直接
if(state.heartStatus){
hearTimer?.cancel();
state.heartStatus = false;
}
}
/**
* 发送心跳包
*/
static void sendHeartPacket(){
Map<String,dynamic> data = {
"code": 9999,
"msg": "心跳包",
};
var jsonData = json.encode(data);
state.webSocket?.sink.add(jsonData);
state.heartStatus = true;
}
/**
* @desc WebSocket心跳包
* @author Marinda
* @date 2022/9/26
*/
static void heartPacket(){
if(state.socketStatus){
hearTimer = Timer(Duration(seconds: state.socketClienTime),() async{
// 重新连接
reconnectSocket();
});
sendHeartPacket();
}
}
/**
* 重新连接socket
*/
static void reconnectSocket(){
destoryHeart();
connectSocket();
}
/**
* @desc 关闭WebSocket
* @author Marinda
* @date 2022/9/26
*/
static Future closeSocket() async{
if(state.webSocket != null){
state.webSocket?.sink.close();
state.webSocket = null;
state.socketStatus = false;
}
}
}
结束
至此笔记到此结束,感谢你的观看!