Flutter开发进阶之使用Socket实现主机服务(二)

Flutter开发进阶之使用Socket实现主机服务(二)

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});
    });
相关推荐
狼头长啸李树身几秒前
眼儿媚·秋雨绵绵窗暗暗
大数据·网络·服务发现·媒体
SizeTheMoment43 分钟前
初识HTTP协议
网络·网络协议·http
哲伦贼稳妥2 小时前
一天认识一个硬件之机房地板
运维·网络·经验分享·其他
早起的年轻人2 小时前
Flutter String 按 ,。分割
flutter
小比卡丘2 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
前行的小黑炭3 小时前
一篇搞定Android 实现扫码支付:如何对接海外的第三方支付;项目中的真实经验分享;如何高效对接,高效开发
android
hgdlip3 小时前
如何快速切换电脑的ip地址
网络·tcp/ip·电脑
落落落sss4 小时前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
程序员-珍4 小时前
虚拟机ip突然看不了了
linux·网络·网络协议·tcp/ip·centos
代码敲上天.5 小时前
数据库语句优化
android·数据库·adb