在Flutter开发实践中,有一些业务是需要主从机合作搭配的服务,其中一些重要的数据和功能是交由主机进行存储和管理,从机再通过UDP和TCP与主机通讯去获得权限,一般在同一个局域网内的多端实现。
在主从机未建立联系之前,主从机除了自身的权限是已知的是不知道任何其他设备的信息的,这时候就需要利用到UDP的广播,因为在局域网中,UDP广播是一种允许设备向网络中的所有其他设备发送消息的技术;
广播地址通常是255.255.255.255,或者网络地址和主机地址的组合,主从机约定好广播的端口后,主机需要监听指定端口的UDP广播。
void udp_listen() async {
// 监听所有可用地址5000端口的广播
_socket = await RawDatagramSocket.bind("0.0.0.0", 5000);
_socket?.listen((event) {
switch (event) {
case RawSocketEvent.read:
Datagram? datagram = _socket?.receive();
if (datagram != null) {
const decoder = Utf8Decoder();
print(decoder.convert(datagram.data));
// 获取到广播信息,内容可能包括指定的加密后信息,可以是广播类型或者IP地址等
}
break;
case RawSocketEvent.write:
break;
case RawSocketEvent.readClosed:
break;
case RawSocketEvent.closed:
break;
}
}, onDone: () {
_socket?.close();
_socket = null;
});
}
主机开启监听后,从机可以发送广播了。
void udp_send() async {
_socket = await RawDatagramSocket.bind("0.0.0.0", 5000);
var message = "xxxxxxxxxx";
final data = Uint8List.fromList(message.codeUnits);
await _socket?.send(data, InternetAddress.anyIPv4, 5000);
}
此时主从机已经完成了数据交互,主机已获知了从机的相关信息,可以建立指定的广播或者直接建立TCP通讯了;
此时我们可以使用flutter_socket_io库进行TCP通信,可以通过创建自定义的连接池来管理连接,连接池可以帮助你重用现有的连接,而不是为每个请求创建新的连接,从而提高性能和效率。
dependencies:
flutter_socket_io: ^latest_version
创建一个自定义的连接池类,这个类将负责管理连接的生命周期和重用现有的连接。
class ConnectionPool {
final int maxConnections = 5; // 设置最大连接数
final String host = '127.0.0.1'; // 设置服务器地址
final int port = 8080; // 设置服务器端口
Map<int, Socket> _pool = {}; // 用于存储连接的映射
int _nextId = 0; // 用于生成唯一的连接ID
Socket getConnection() {
int id = _nextId++;
Socket socket = Socket.fromAddress(host, port);
_pool[id] = socket;
return socket;
}
void releaseConnection(Socket socket) {
// 在这里实现连接释放的逻辑,例如关闭连接等操作
}
}
以下是一些简单的示例,实际开发中还需注意后续的线程安全、各种网络异常等问题。
Socket socket = connectionPool.getConnection();
socket.listen((data) {
print('Received: $data');
});
Future<String> sendMessage(String message) async {
try {
Socket socket = connectionPool.getConnection(); // 获取连接
// 使用socket发送消息并处理响应
socket.write('你要发送的消息');
// ...
socket.close(); // 释放连接
return 'Message sent successfully';
} catch (e) {
print('Error sending message: ${e.toString()}');
return 'Failed to send message';
}
}