Flutter网络通信插件whimstech_socket_dart的使用
Flutter网络通信插件whimstech_socket_dart的使用
版本信息
whimstech-socket-dart | Socket.io Server |
---|---|
v0.9.* ~ v1.* |
v2.* |
v2.* |
v3.* ~ v4.6.* |
v3.* |
v4.7.* ~ v4.* |
使用方法
Dart服务器
import 'package:socket_io/socket_io.dart';
void main() {
// Dart服务器
var io = Server();
var nsp = io.of('/some');
nsp.on('connection', (client) {
print('连接 /some');
client.on('msg', (data) {
print('来自 /some 的数据 => $data');
client.emit('fromServer', "ok 2");
});
});
io.on('connection', (client) {
print('默认命名空间的连接');
client.on('msg', (data) {
print('来自默认的 数据 => $data');
client.emit('fromServer', "ok");
});
});
io.listen(3000);
}
Dart客户端
import 'package:socket_io_client/socket_io_client.dart' as IO;
void main() {
// Dart客户端
IO.Socket socket = IO.io('http://localhost:3000');
socket.onConnect((_) {
print('连接成功');
socket.emit('msg', 'test');
});
socket.on('event', (data) => print(data));
socket.onDisconnect((_) => print('断开连接'));
socket.on('fromServer', (_) => print(_));
}
手动连接
为了手动连接套接字,设置选项 autoConnect: false
并调用 .connect()
。
例如:
Socket socket = IO.io('http://localhost:3000',
OptionBuilder()
.setTransports(['websocket']) // 为 Flutter 或 Dart VM
.disableAutoConnect() // 禁用自动连接
.setExtraHeaders({'foo': 'bar'}) // 可选
.build()
);
socket.connect();
请注意,如果 autoConnect: true
(默认情况下启用),则不应调用 .connect()
,否则会导致所有事件处理程序被注册/触发两次。参见Issue #33。
更新额外的头部
Socket socket = ... // 创建套接字。
socket.io.options['extraHeaders'] = {'foo': 'bar'}; // 更新额外的头部。
socket.io..disconnect()..connect(); // 手动重新连接套接字。
带确认的发送
Socket socket = ... // 创建套接字。
socket.onConnect((_) {
print('连接成功');
socket.emitWithAck('msg', 'init', ack: (data) {
print('确认 $data') ;
if (data != null) {
print('来自服务器 $data');
} else {
print("空");
}
});
});
套接字连接事件
这些事件可以监听。
const List EVENTS = [
'connect',
'connect_error',
'disconnect',
'error',
'reconnect',
'reconnect_attempt',
'reconnect_failed',
'reconnect_error',
'ping',
'pong'
];
// 替换 'onConnect' 为上述任意一个事件。
socket.onConnect((_) {
print('连接成功');
});
确认已收到套接字服务器的事件
socket.on('eventName', (data) {
final dataList = data as List;
final ack = dataList.last as Function;
ack(null);
});
在Flutter中的使用
在Flutter环境中(非Flutter Web环境),它仅支持 dart:io
WebSocket,
而不是 dart:html
WebSocket 或 Ajax (XHR),因此在这种情况下
创建套接字实例时需要添加 setTransports(['websocket'])
。
例如:
IO.Socket socket = IO.io('http://localhost:3000',
OptionBuilder()
.setTransports(['websocket']) // 为 Flutter 或 Dart VM
.setExtraHeaders({'foo': 'bar'}) // 可选
.build());
在Flutter中使用流和StreamBuilder
import 'dart:async';
// 步骤1: 流设置
class StreamSocket {
final _socketResponse = StreamController<String>();
void Function(String) get addResponse => _socketResponse.sink.add;
Stream<String> get getResponse => _socketResponse.stream;
void dispose() {
_socketResponse.close();
}
}
StreamSocket streamSocket = StreamSocket();
// 步骤2: 在 main.dart 文件的主函数中添加此函数,并将传入的数据添加到流中
void connectAndListen() {
IO.Socket socket = IO.io('http://localhost:3000',
OptionBuilder()
.setTransports(['websocket']).build());
socket.onConnect((_) {
print('连接成功');
socket.emit('msg', 'test');
});
// 当从服务器接收到事件时,数据会被添加到流中
socket.on('event', (data) => streamSocket.addResponse);
socket.onDisconnect((_) => print('断开连接'));
}
// 步骤3: 使用StreamBuilder构建小部件
class BuildWithSocketStream extends StatelessWidget {
const BuildWithSocketStream({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: StreamBuilder(
stream: streamSocket.getResponse,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
return Container(
child: snapshot.data,
);
},
),
);
}
}
处理套接字缓存和后续查找的重要注意事项
查找协议
我们基于相同的方案/端口/主机重用现有实例。
重要的是要明确,dispose()
和 destroy()
不会从已知连接的缓存中删除主机。如果不正确地处理,这可能会导致后续连接忽略某些配置部分。必须通过在第一次创建实例时使用OptionBuilder中的可用选项来处理这种情况。
示例
以下示例中,为该连接设置了用户ID和用户名作为额外的头部。 如果你尝试以更新后的值创建相同的连接,如果主机相同,则不会更新额外的头部,而返回旧的连接。
_socket = IO.io(
host,
IO.OptionBuilder()
.setTransports(['websocket'])
.setExtraHeaders({'id': userId, 'name': username})
.disableAutoConnect()
.enableReconnection()
.build());
为了避免这种情况,根据你的应用程序需求,你可以使用 enableForceNew()
或 disableMultiplex()
到选项构建器。这些选项将修改使用相同主机的所有连接,所以请务必注意并计划好。
另一种选择,如果你的应用场景适合,可以在上面提到的更新额外的头部中遵循使用方式。 通过在构建选项之外更新额外的头部,你可以保证你的连接将具有你期望的值。
故障排除
无法连接HTTPS服务器或自签名证书服务器
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext context) {
return super.createHttpClient(context)
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
}
void main() {
HttpOverrides.global = MyHttpOverrides();
runApp(MyApp());
}
iOS关闭套接字时出现内存泄漏问题
- 参考此处问题。
请使用
socket.dispose()
而不是socket.close()
或socket.disconnect()
来解决iOS上的内存泄漏问题。
macOS上连接错误:SocketException: 连接失败
- 参考此处问题。
在文件 <*.entitlements>
中的目录 <macos/Runner/>
下添加以下键:
<key>com.apple.security.network.client</key>
<true/>
更多关于Flutter网络通信插件whimstech_socket_dart的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter网络通信插件whimstech_socket_dart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
whimstech_socket_dart
是一个用于 Flutter 的 Dart 插件,提供了基于 WebSocket 的网络通信功能。它允许你在 Flutter 应用中轻松地建立 WebSocket 连接,并发送和接收消息。
安装
首先,你需要在 pubspec.yaml
文件中添加依赖:
dependencies:
whimstech_socket_dart: ^1.0.0
然后运行 flutter pub get
来安装依赖。
基本用法
- 导入包
import 'package:whimstech_socket_dart/whimstech_socket_dart.dart';
- 创建 WebSocket 连接
final socket = WebSocket('wss://your.websocket.url');
- 监听连接状态
socket.onOpen.listen((event) {
print('WebSocket connection opened');
});
socket.onClose.listen((event) {
print('WebSocket connection closed');
});
socket.onError.listen((error) {
print('WebSocket error: $error');
});
- 发送消息
socket.send('Hello, WebSocket!');
- 接收消息
socket.onMessage.listen((message) {
print('Received message: $message');
});
- 关闭连接
socket.close();
完整示例
以下是一个完整的示例,展示了如何使用 whimstech_socket_dart
进行基本的 WebSocket 通信:
import 'package:flutter/material.dart';
import 'package:whimstech_socket_dart/whimstech_socket_dart.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: WebSocketExample(),
);
}
}
class WebSocketExample extends StatefulWidget {
[@override](/user/override)
_WebSocketExampleState createState() => _WebSocketExampleState();
}
class _WebSocketExampleState extends State<WebSocketExample> {
late WebSocket socket;
final TextEditingController _controller = TextEditingController();
List<String> messages = [];
[@override](/user/override)
void initState() {
super.initState();
_initWebSocket();
}
void _initWebSocket() {
socket = WebSocket('wss://your.websocket.url');
socket.onOpen.listen((event) {
print('WebSocket connection opened');
});
socket.onClose.listen((event) {
print('WebSocket connection closed');
});
socket.onError.listen((error) {
print('WebSocket error: $error');
});
socket.onMessage.listen((message) {
setState(() {
messages.add('Received: $message');
});
});
}
void _sendMessage() {
if (_controller.text.isNotEmpty) {
socket.send(_controller.text);
setState(() {
messages.add('Sent: ${_controller.text}');
});
_controller.clear();
}
}
[@override](/user/override)
void dispose() {
socket.close();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebSocket Example'),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: messages.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(messages[index]),
);
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: 'Enter a message',
),
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: _sendMessage,
),
],
),
),
],
),
);
}
}