Flutter局域网客户端服务器通信插件client_server_lan的使用
Flutter局域网客户端服务器通信插件client_server_lan的使用
插件简介
client_server_lan
是一个基于 Flutter 的局域网通信插件,支持客户端与服务器之间的双向通信。它移除了 Node Commander
中的一些复杂功能(如指挥节点),专注于简单的客户端与服务器通信。
使用方法
1. 配置 Android 文件
在 android/app/AndroidManifest.xml
文件中添加以下配置:
<application ...
android:networkSecurityConfig="@xml/network_security_config" >
<meta-data android:name="io.flutter.network-policy"
android:resource="@xml/network_security_config"/>
</application>
然后在 android/app/src/main/res/xml/
目录下创建 network_security_config.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
2. 启动服务器节点
以下是启动服务器节点的代码示例:
import 'dart:async';
import 'package:client_server_lan/client_server_lan.dart';
ServerNode server;
void startServer() async {
server = ServerNode(
name: "server_name", // 任意文本名称
verbose: true, // 调试输出
onDispose: onDispose, // 服务器释放时执行的回调
clientDispose: clientDispose, // 客户端释放时执行的回调
);
await server.init(); // 初始化服务器
await server.onReady; // 等待服务器准备就绪
// 更新状态
setState(() {
serverStatus = "Server ready on ${server.host}:${server.port}";
});
// 监听数据接收
server.dataResponse.listen((DataPacket data) {
setState(() {
String dataReceived = data.payload;
});
});
}
3. 启动客户端节点
以下是启动客户端节点的代码示例:
import 'dart:async';
import 'package:client_server_lan/client_server_lan.dart';
ClientNode client;
void startClient() async {
client = ClientNode(
name: "client_name", // 任意文本名称
verbose: true, // 调试输出
onDispose: onDispose, // 客户端释放时执行的回调
);
await client.init(); // 初始化客户端
await client.onReady; // 等待客户端准备就绪
// 更新状态
setState(() {
clientStatus = "Client ready on ${client.host}:${client.port}";
});
// 监听数据接收
client.dataResponse.listen((DataPacket data) {
setState(() {
String dataReceived = data.payload;
});
});
}
4. 扫描客户端节点
服务器可以通过以下方式扫描在线的客户端节点:
void findClients() async {
server.discoverNodes(); // 开始扫描客户端
await Future.delayed(const Duration(seconds: 2)); // 等待扫描完成
// 更新状态并列出所有已连接的客户端
setState(() {
clientIPs = "";
});
for (final s in server.clientsConnected) {
setState(() {
clientIPs += "id=${s.name},IP=${s.address}\n";
});
}
}
5. 数据传输
从客户端发送数据到服务器
void clientToServer(String dataToSend) async {
await client.sendData(dataToSend, "userInfo"); // 发送数据
}
从服务器发送数据到客户端
void serverToClient(String dataToSend, String clientName) async {
final String client = server.clientUri(clientName); // 获取客户端地址
await server.sendData(dataToSend, "userInfo", client); // 发送数据
}
示例代码
以下是完整的示例代码,展示了如何使用 client_server_lan
插件实现客户端与服务器通信:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:client_server_lan/client_server_lan.dart';
import 'package:device_info/device_info.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'UDPLANtransfer',
theme: ThemeData(
primarySwatch: Colors.green,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
[@override](/user/override)
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool kIsAndroid = false;
String dropdownValue = 'Server';
bool isLoading = false;
String dataReceived = '';
bool isRunning = false;
String status = '';
// Server
ServerNode server;
List<ConnectedClientNode> connectedClientNodes = [];
// Client
ClientNode client;
[@override](/user/override)
Widget build(BuildContext context) {
kIsAndroid = !kIsWeb && Theme.of(context).platform == TargetPlatform.android;
return Scaffold(
appBar: AppBar(
title: Text('UDPLANtransfer'),
),
body: Container(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildDropdown(),
Expanded(
child: dropdownValue == 'Server'
? ServerPage(
onStartPressed: startServer,
onDisposePressed: disposeServer,
connectedClientNodes: connectedClientNodes,
onFindClientsPressed: findClients,
onSendToClient: serverToClient,
dataReceived: dataReceived,
isLoading: isLoading,
isRunning: isRunning,
status: status,
)
: ClientPage(
onStartPressed: startClient,
onDisposePressed: disposeClient,
onSendToServer: clientToServer,
dataReceived: dataReceived,
onCheckServerPressed: checkServerExistance,
isLoading: isLoading,
isRunning: isRunning,
status: status,
),
),
],
),
),
);
}
DropdownButton<String> _buildDropdown() {
return DropdownButton<String>(
value: dropdownValue,
disabledHint: Text(dropdownValue),
onChanged: !isRunning
? (String newValue) {
setState(() {
dropdownValue = newValue;
});
}
: null,
items: ['Server', 'Client']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
void startServer() async {
var name = 'Server';
if (kIsAndroid) {
var deviceInfo = await DeviceInfoPlugin().androidInfo;
name = 'Server-${deviceInfo.brand}-${deviceInfo.model}';
}
setState(() {
isLoading = true;
server = ServerNode(
name: name,
verbose: true,
onDispose: onDisposeServer,
clientDispose: clientDispose,
onError: onError,
);
});
await server.init();
await server.onReady;
setState(() {
status = 'Server ready on ${server.host}:${server.port} (${server.name})';
isRunning = true;
isLoading = false;
});
server.dataResponse.listen((DataPacket data) {
setState(() {
dataReceived = data.payload.toString();
});
});
}
void disposeServer() {
setState(() {
isLoading = true;
});
server.dispose();
}
void onDisposeServer() {
setState(() {
isRunning = false;
status = 'Server is not running';
isLoading = false;
connectedClientNodes = [];
});
}
void clientDispose(ConnectedClientNode c) async {
setState(() {
connectedClientNodes = [];
});
for (final s in server.clientsConnected) {
setState(() {
connectedClientNodes.add(s);
});
}
}
void findClients() async {
await server.discoverNodes();
await Future.delayed(const Duration(seconds: 2));
setState(() {
connectedClientNodes = [];
});
for (final s in server.clientsConnected) {
setState(() {
connectedClientNodes.add(s);
});
}
}
void serverToClient(String clientName, dynamic message) async {
final client = server.clientUri(clientName);
await server.sendData(message, 'userInfo', client);
}
void startClient() async {
var name = 'Client';
if (kIsAndroid) {
var deviceInfo = await DeviceInfoPlugin().androidInfo;
name = 'Client-${deviceInfo.brand}-${deviceInfo.model}';
}
setState(() {
isLoading = true;
client = ClientNode(
name: name,
verbose: true,
onDispose: onDisposeClient,
onServerAlreadyExist: onServerAlreadyExist,
onError: onError,
);
});
await client.init();
await client.onReady;
setState(() {
status = 'Client ready on ${client.host}:${client.port} (${client.name})';
isRunning = true;
isLoading = false;
});
client.dataResponse.listen((DataPacket data) {
setState(() {
if (data.payload.runtimeType == String) {
dataReceived = data.payload;
} else {
dataReceived = City.fromMap(data.payload).toString();
}
});
});
}
void disposeClient() {
client.dispose();
}
void onDisposeClient() {
setState(() {
isRunning = false;
status = 'Client is not running';
isLoading = false;
});
}
Future<void> onServerAlreadyExist(DataPacket dataPacket) async {
print('Server already exist on ${dataPacket.host} (${dataPacket.name})');
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Server Already Exist'),
content:
Text('Server ready on ${dataPacket.host} (${dataPacket.name})'),
actions: [
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('CLOSE'),
),
],
);
},
);
}
Future<void> checkServerExistance() async {
await client.discoverServerNode();
}
void clientToServer(dynamic message) async {
await client.sendData(message, 'userInfo');
}
Future<void> onError(String error) async {
print('ERROR $error');
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Error'),
content: Text(error),
actions: [
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('CLOSE'),
),
],
);
},
);
}
}
更多关于Flutter局域网客户端服务器通信插件client_server_lan的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter局域网客户端服务器通信插件client_server_lan的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
client_server_lan
是一个用于在局域网内进行客户端和服务器通信的 Flutter 插件。它允许你在同一局域网内的设备之间进行数据传输,适用于需要设备间通信的应用场景,如文件共享、聊天应用、多人游戏等。
安装插件
首先,你需要在 pubspec.yaml
文件中添加 client_server_lan
插件的依赖:
dependencies:
flutter:
sdk: flutter
client_server_lan: ^0.0.1 # 请检查最新版本
然后运行 flutter pub get
来安装插件。
使用插件
1. 创建服务器
在服务器端,你可以使用 Server
类来创建一个服务器并监听客户端的连接请求。
import 'package:client_server_lan/client_server_lan.dart';
void startServer() async {
Server server = Server();
server.onClientConnected.listen((client) {
print('Client connected: ${client.address}');
client.onData.listen((data) {
print('Received from client: $data');
client.send('Hello from server!');
});
client.onDisconnected.listen((_) {
print('Client disconnected: ${client.address}');
});
});
await server.start(port: 8080);
print('Server started on port 8080');
}
2. 创建客户端
在客户端,你可以使用 Client
类来连接到服务器并发送数据。
import 'package:client_server_lan/client_server_lan.dart';
void connectToServer() async {
Client client = Client();
await client.connect('192.168.1.100', 8080); // 替换为服务器的IP地址
client.onData.listen((data) {
print('Received from server: $data');
});
client.onDisconnected.listen((_) {
print('Disconnected from server');
});
client.send('Hello from client!');
}
3. 在 Flutter 应用中使用
你可以在 Flutter 应用中使用上述代码来启动服务器或连接到服务器。例如,你可以在一个按钮的 onPressed
回调中调用 startServer
或 connectToServer
函数。
import 'package:flutter/material.dart';
import 'package:client_server_lan/client_server_lan.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Client Server LAN Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: startServer,
child: Text('Start Server'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: connectToServer,
child: Text('Connect to Server'),
),
],
),
),
),
);
}
}