Flutter开发进阶之使用Socket实现主机服务(二)
在完成局域网内设备定位后就可以进入微服务的实操了。
I、构建Socket连接池
一、定义Socket
使用socket_io_client
yaml
socket_io_client: ^2.0.3+1
导入头文件
dart
import 'package:socket_io_client/socket_io_client.dart' as io;
定义属性
dart
class _SocketIoObject {
/// 连接
io.Socket? socket;
/// 连接次数
int count = 0;
/// 创建的时间
int createTime = 0;
/// 根据连接频率获取的优先级
double proportion = 0;
}
二、定义连接池
dart
class SocketIoPool {
/// 连接池本身
static Map<String, dynamic> sockets = {};
/// 连接最大数量
static int maxCount = 10;
/// 根据优先级获取到
/// 最应该销毁的连接的key
static String exitKey = "";
}
三、连接池运行逻辑
连接排序
dart
/// 将连接按照优先级排序
/// 使用频率越低的连接的优先级越高
/// 可以被销毁
///
static void _sortSocket() {
int now = DateTime.now().millisecondsSinceEpoch;
double maxProportion = 0;
sockets.forEach((key, value) {
value.proportion = (now - value.createTime) / value.count;
if (value.proportion > maxProportion) {
maxProportion = value.proportion;
exitKey = key;
}
});
}
连接创建
dart
/// 创建新连接时限制最大连接数量
///
static io.Socket _newSocket(String host, int port) {
if (sockets.length >= maxCount && exitKey.isNotEmpty) {
_SocketIoObject? object = sockets[exitKey];
if (object != null) {
object.socket?.disconnect();
object.socket?.dispose();
sockets.remove(exitKey);
}
}
String relative = "$host:$port";
io.Socket socket = io.io(relative);
sockets[relative] = _SocketIoObject()
..socket = socket
..count = 1
..createTime = DateTime.now().millisecondsSinceEpoch;
Future(() => _sortSocket());
return socket;
}
连接获取
dart
/// 尽量复用连接
/// 没有再创建
///
static io.Socket? getSocket(String host, int port) {
String relative = "$host:$port";
if (sockets.containsKey(relative)) {
sockets[relative]?.count++;
Future(() => _sortSocket());
return sockets[relative]?.socket;
}
return _newSocket(host, port);
}
II、构建数据库
一、对应表的创建
使用sqflite
yaml
sqflite: ^2.3.2
导入头文件
dart
import 'package:sqflite/sqflite.dart';
定义表
dart
class Animal {
int? id;
int? age;
double? height;
int? gender;
String? name;
String? species;
String? family;
Animal({
this.id,
this.age,
this.height,
this.gender,
this.name,
this.species,
this.family,
});
factory Animal.fromJson(Map<String, dynamic> map) {
return Animal(
id: map["id"],
age: map["age"],
height: map["height"],
gender: map["gender"],
name: map["name"],
species: map["species"],
family: map["family"]);
}
/// 类名
static String className<T>() {
return T.toString();
}
/// 创建表
static Future<void> createTable(Database db) async {
final batch = db.batch();
batch.execute(createTableSql);
await batch.commit();
}
}
注意:为提高并发性能,尽量使用事务管理,
When committed with [Batch.commit], sqflite will manage a transaction to
execute statements in the batch. If this [batch] method has been called on a [Transaction], committing the batch is deferred to when the transaction
completes (but [Batch.apply] or [Batch.commit] still need to be called).
体现在sqflite中就是使用Batch或者transaction。
二、定义sql语句
dart
/// 插入数据
String get insertSql =>
"INSERT OR REPLACE INTO ${Animal.className()} (id,age,height,gender,name,species,family) VALUES ($id,$age,$height,$gender,$name,$species,$family)";
/// 更新数据
String get updateSql =>
"UPDATE ${Animal.className()} SET age = $age, height = $height, gender = $gender, name = $name, species = $species, family = $family WHERE id = $id";
/// 删除数据
String get deleteSql => "DELETE FROM ${Animal.className()} WHERE id = $id";
/// 查询所有
static String get allSql => "SELECT * FROM ${Animal.className()}";
/// 删除表
static String get clearSql => "DROP TABLE ${Animal.className()}";
/// 查询某条
static String get oneSql =>
"SELECT * FROM ${Animal.className()} WHERE id = ?";
三、定义数据库管理器
dart
class SqfliteManager {
/// 数据库名称 一般为xx.db
String dbName;
/// 数据库版本
int version;
SqfliteManager({
required this.dbName,
required this.version,
});
}
数据库的获取
dart
Database? _database;
Future<String> get _databasePath async {
final databasePath = await getDatabasesPath();
return "$databasePath/$dbName";
}
/// 获取数据库
Future<Database?> get database async {
if (_database == null) {
String path = await _databasePath;
_database =
await openDatabase(path, version: version, onCreate: (db, v) async {
/// 创建数据库时
}, onConfigure: (db) {
/// 数据库配置时,在创建前、升降级前
}, onDowngrade: (db, oldV, newV) {
/// 数据库降级时
}, onUpgrade: (db, oldV, newV) {
/// 数据库升级时
}, onOpen: (db) {
/// 数据库打开时
});
}
return _database;
}
四、对应的数据库操作指令
dart
/// 销毁数据库
Future<void> cancelDatabase() async {
String path = await _databasePath;
return deleteDatabase(path);
}
/// 数据库关闭
Future<void> closeDatabase() async {
if (_database?.isOpen == true) {
await _database?.close();
}
_database = null;
}
/// 插入动物数据
Future<void> insertAnimal(Animal animal) async {
await database.then(
(db) async => await db?.transaction(
(txn) async => await txn.rawInsert(animal.insertSql),
),
);
}
/// 更新动物数据
Future<void> updateAnimal(Animal animal) async {
await database.then(
(db) async => await db?.transaction(
(txn) async => await txn.rawUpdate(animal.updateSql),
),
);
}
/// 删除动物数据
Future<void> deleteAnimal(Animal animal) async {
await database.then(
(db) async => await db?.transaction(
(txn) async => await txn.rawDelete(animal.deleteSql),
),
);
}
/// 查询所有动物数据
Future<List<Animal>?> allAnimals() async {
final db = await database;
final batch = db?.batch();
batch?.rawQuery(Animal.allSql);
List<Map<String, dynamic>>? maps =
await batch?.commit() as List<Map<String, dynamic>>?;
return maps?.map((e) => Animal.fromJson(e)).toList();
}
/// 删除动物数据表
Future<void> deleteAnimalTable() async {
await database.then(
(db) async => await db?.transaction(
(txn) async => await txn.rawDelete(Animal.clearSql),
),
);
}
/// 查询单条动物数据
Future<Animal?> findAnimal(int id) async {
final db = await database;
final batch = db?.batch();
batch?.rawQuery(Animal.oneSql, [id]);
List<Map<String, dynamic>>? maps =
await batch?.commit() as List<Map<String, dynamic>>?;
return maps?.map((e) => Animal.fromJson(e)).toList().first;
}
III、执行通讯
dart
final a = SocketIoPool.getSocket('http://192.168.0.1', 80);
a?.connect();
a?.on('getAnimals', (data) {
a.emit('getAnimalsResponse', {data: animals});
});