Flutter高速数据传输插件uhst的使用

Flutter高速数据传输插件uhst的使用

User Hosted Secure Transmission (UHST) 是一个用于 Flutter 应用的 Dart 客户端库。它支持以下功能:

  • 从客户端发送消息并监听主机广播的消息。
  • 主机可以广播消息。
  • 主机可以监听来自多个客户端的消息。

关于

UHST 是用户托管安全传输框架的客户端库。它可以实现以下功能:

  • 发送消息从客户端到主机,并监听主机广播的消息。
  • 主机广播消息。
  • 主机监听来自多个客户端的消息。

你可以查看 GitHub 上的实现示例 和源码。

请注意当前版本的限制:

  • 它只支持字符串类型的消息。
  • 需要一个实现了 UHST 协议的服务器。你可以查看一个现成的服务器示例 GitHub

支持和讨论

请加入我们的 Gitter 或者在 StackOverflow 上提问。

使用

假设你已经加载了库,首先创建一个新的实例:

var uhst = UHST();

你可以查阅文档了解更多可以传递的选项(包括你的自己的 Relay 服务器 URL、WebRTC 配置等)。

主机

在 UHST 中,主机是一个每个其他对等体连接的节点。这个概念类似于多人游戏中监听服务器的角色。

请确保在重新连接到另一个主机之前关闭之前的连接。

创建一个新的主机的最简单方法如下:

var host = uhst.host("testHost");

host?.disconnect();

host
  ?..onReady(handler: ({required String hostId}) {
    setState(() {
      hostMessages.add('Host Ready! Using $hostId');
      print('host is ready!');
      _hostIdController.text = hostId;
    });
  })
  ..onException(handler: ({required dynamic exception}) {
    print('exception received! $exception');
    if (exception is HostIdAlreadyInUse) {
      // 如果刷新页面,这是预期的情况
      // 连接仍然在 Relay 上
      // 只需等待即可
      setState(() {
        hostMessages
            .add('HostId already in use, retrying in 15 seconds...!');
      });
    } else {
      setState(() {
        hostMessages.add(exception.toString());
      });
    }
  })
  ..onConnection(handler: ({required UhstSocket uhstSocket}) {
    uhstSocket.onDiagnostic(handler: ({required String message}) {
      setState(() {
        hostMessages.add(message);
      });
    });

    uhstSocket.onMessage(handler: ({required message}) {
      setState(() {
        hostMessages
            .add("Host received: $message");
        host?.broadcastString(message: message);
      });
    });

    uhstSocket.onOpen(handler: () {
      // uhstSocket.sendString(message: 'Host sent message!');
    });
  });
}

注意,请求的主机 ID 可能不会被信号服务器接受,你应该始终在连接到主机时使用 hostId 接收到的 ready 事件后的 hostId

客户端

要从另一个浏览器连接到主机,请使用你在 onReady 事件期间接收的相同 hostId

请确保在重新连接到另一个主机之前关闭之前的连接。

var client = uhst.join("testHost");

client?.close();

client
  ?..onOpen(handler: () {
    setState(() {
      client?.sendString(message: 'Hello host!');
    });
  })
  ..onMessage(handler: ({required message}) {
    setState(() {
      clientMessages.add('Client received: $message');
    });
  })
  ..onException(handler: ({required dynamic exception}) {
    if (exception is InvalidHostId || exception is InvalidClientOrHostId) {
      setState(() {
        clientMessages.add('Invalid hostId!');
      });
    } else {
      setState(() {
        clientMessages.add(exception.toString());
      });
    }
  })
  ..onDiagnostic(handler: ({required String message}) {
    setState(() {
      clientMessages.add(message);
    });
  });

UHST 客户端接口类似于 HTML5 WebSocket 接口,但与专用服务器不同的是,一个对等体充当主机供其他对等体加入。

一旦客户端和主机连接,它们就可以异步交换消息。任意数量的客户端可以连接到同一个主机,但是客户端不能互相发送消息,只能与主机通信。

清理

记得调用 .dispose() 来取消所有订阅并断开主机套接字与服务器、客户端与主机的连接。

在 Flutter 中,你可以在 dispose 覆盖方法中添加这样的方法:

[@override](/user/override)
void dispose() {
  client?.dispose();
  host?.dispose();
  super.dispose();
}

完整示例代码

以下是完整的示例代码,展示了如何使用 UHST 插件进行数据传输:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:uhst/uhst.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) => MaterialApp(
        title: 'Flutter UHST Example',
        theme:
            ThemeData(primarySwatch: Colors.blue, brightness: Brightness.dark),
        home: const MyHomePage(title: 'Flutter UHST Example'),
      );
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({
    required this.title,
    Key? key,
  }) : super(key: key);

  final String title;

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> hostMessages = [];
  final List<String> clientMessages = [];
  UHST? uhst;
  UhstHost? host;
  UhstSocket? client;
  final TextEditingController _hostIdController = TextEditingController();

  Future<void> startHosting() async {
    initUHST();
    host?.disconnect();
    host = uhst?.host();
    host
      ?..onReady(handler: ({required hostId}) {
        hostMessages.add('Host Ready! Using hostId $hostId');
        print('host is ready!');
        _hostIdController.text = hostId;
        setState(() {});
      })
      ..onException(handler: ({required dynamic exception}) {
        if (exception is RelayException) {
          hostMessages.add('disconneted! $exception');
        } else {
          hostMessages.add('exception received! $exception');
        }
        setState(() {});
      })
      ..onClose(handler: ({required hostId}) {
        hostMessages.add('Host $hostId disconnected');
        setState(() {});
      })
      ..onConnection(handler: ({required UhstSocket uhstSocket}) {
        uhstSocket
          ..onDiagnostic(handler: ({required message}) {
            hostMessages.add(message);
            setState(() {});
          })
          ..onMessage(handler: ({required message}) {
            hostMessages
                .add('Host received: $message from ${uhstSocket.remoteId}');
            setState(() {});
            host?.broadcastString(message: message);
          })
          ..onOpen(handler: () {
            hostMessages.add('Client ${uhstSocket.remoteId} connected');
            setState(() {});
          })
          ..onClose(handler: ({required hostId}) {
            hostMessages.add('Client $hostId disconected');
            setState(() {});
          });
      });
  }

  Future<void> stopHosting() async => host?.disconnect();
  void initUHST() {
    uhst ??= UHST(
      debug: true,
      // relayUrl: 'http://127.0.0.1:3000',
    );
  }

  Future<void> join() async {
    initUHST();
    client?.close();
    client = uhst?.join(hostId: _hostIdController.text);
    client
      ?..onException(handler: ({required dynamic exception}) {
        final text = '[EXCEPION]: ${exception.toString()}';
        if (exception is InvalidHostId || exception is InvalidClientOrHostId) {
          clientMessages.add('[EXCEPION]: Invalid hostId!');
        } else if (exception is HostDisconnected) {
          clientMessages.add(text);
        } else {
          clientMessages.add(text);
        }
        setState(() {});
      })
      ..onDiagnostic(handler: ({required message}) {
        clientMessages.add(message);
        setState(() {});
      })
      ..onOpen(handler: () {
        clientMessages.add('Client connected to host: ${client?.remoteId}');
        setState(() {});
      })
      ..onClose(handler: ({required hostId}) {
        clientMessages.add('Connection to host $hostId dropped.');
        setState(() {});
      })
      ..onMessage(handler: ({required message}) {
        clientMessages.add('Client received: $message');
        setState(() {});
      });
  }

  Future<void> diconnect() async => client?.close();
  [@override](/user/override)
  void dispose() {
    client?.dispose();
    host?.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Row(
          children: [
            Flexible(
              flex: 2,
              child: Material(
                elevation: 4,
                child: Container(
                  padding: const EdgeInsets.all(10),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Center(
                        child: Text('Host'),
                      ),
                      const Divider(height: 22),
                      TextField(
                        decoration: const InputDecoration(labelText: 'Host id'),
                        controller: _hostIdController,
                      ),
                      const SizedBox(height: 20),
                      Wrap(
                        children: [
                          const Text('Host actions:'),
                          ...[
                            TextButton(
                              onPressed: startHosting,
                              child: const Text('Start hosting'),
                            ),
                            TextButton(
                              onPressed: stopHosting,
                              child: const Text('Finish hosting'),
                            ),
                            TextButton(
                              onPressed: () {
                                hostMessages.clear();
                                setState(() {});
                              },
                              child: const Text('Clear host messages'),
                            ),
                          ].map(
                            (w) => Padding(
                              padding: const EdgeInsets.only(left: 20),
                              child: w,
                            ),
                          )
                        ],
                      ),
                      const Divider(
                        thickness: 1,
                      ),
                      const SizedBox(height: 20),
                      const Center(
                        child: Text('Host chat &amp; debug messages'),
                      ),
                      const SizedBox(height: 20),
                      Expanded(
                        child: ListView.builder(
                          itemBuilder: (context, index) =>
                              Text(hostMessages[index]),
                          itemCount: hostMessages.length,
                        ),
                      )
                    ],
                  ),
                ),
              ),
            ),
            Flexible(
              flex: 2,
              child: Padding(
                padding: const EdgeInsets.all(10),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Center(child: Text('Client')),
                    const Divider(height: 22),
                    Wrap(
                      children: [
                        const Text('Client actions:'),
                        ...[
                          TextButton(
                            onPressed: join,
                            child: const Text('Join a host'),
                          ),
                          TextButton(
                            onPressed: diconnect,
                            child: const Text('Leave a host'),
                          ),
                          TextButton(
                            onPressed: () {
                              clientMessages.clear();
                              setState(() {});
                            },
                            child: const Text('Clear client messages'),
                          ),
                        ].map(
                          (w) => Padding(
                            padding: const EdgeInsets.only(left: 20),
                            child: w,
                          ),
                        )
                      ],
                    ),
                    const Divider(height: 22),
                    TextField(
                      controller: _hostIdController,
                      decoration: InputDecoration(
                        labelText: 'Client messsage',
                        suffix: IconButton(
                          icon: const Icon(Icons.send),
                          onPressed: () {
                            if (client == null) {
                              clientMessages.add(
                                'No client initialized! '
                                'Start hosting and join a host first',
                              );
                            }

                            client?.sendString(
                                message: _hostIdController.text);
                            _hostIdController.clear();
                            setState(() {});
                          },
                        ),
                      ),
                    ),
                    const SizedBox(height: 20),
                    const Center(child: Text('Client chat and debug messages')),
                    const SizedBox(height: 20),
                    Expanded(
                      child: ListView.builder(
                        itemBuilder: (context, index) =>
                            Text(clientMessages[index]),
                        itemCount: clientMessages.length,
                      ),
                    )
                  ],
                ),
              ),
            )
          ],
        ),
      );

  [@override](/user/override)
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties
      ..add(IterableProperty<String>('hostMessages', hostMessages))
      ..add(DiagnosticsProperty<UHST?>('uhst', uhst))
      ..add(DiagnosticsProperty<TextEditingController>('hostTextFieldController', _hostIdController))
      ..add(DiagnosticsProperty<UhstSocket?>('client', client))
      ..add(IterableProperty<String>('clientMessages', clientMessages))
      ..add(DiagnosticsProperty<UhstHost?>('host', host));
  }
}

更多关于Flutter高速数据传输插件uhst的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter高速数据传输插件uhst的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用UHST(Ultra High-Speed Transfer)插件来实现高速数据传输的示例代码。UHST 插件允许开发者在Flutter应用中实现高效、快速的数据传输。

首先,确保你的Flutter开发环境已经配置好,然后你可以按照以下步骤来集成和使用UHST插件。

1. 添加依赖

在你的pubspec.yaml文件中添加UHST插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  uhst: ^latest_version  # 请替换为最新的版本号

然后运行flutter pub get来安装依赖。

2. 初始化UHST

在你的Flutter应用中,你需要初始化UHST客户端。这通常在你的应用的主入口文件中完成,比如main.dart

import 'package:flutter/material.dart';
import 'package:uhst/uhst.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late UhstClient uhstClient;

  @override
  void initState() {
    super.initState();
    // 初始化UHST客户端
    uhstClient = UhstClient(
      apiKey: 'YOUR_UHST_API_KEY',  // 请替换为你的UHST API密钥
    );

    // 监听连接状态变化
    uhstClient.onStatusChange.listen((status) {
      print('UHST status changed: $status');
    });

    // 监听数据接收事件
    uhstClient.onData.listen((data) {
      print('Received data: ${String.fromCharCodes(data)}');
    });

    // 连接到UHST服务器(假设你已经有了房间ID)
    uhstClient.connect('ROOM_ID').then((_) {
      print('Connected to UHST room.');
    }).catchError((error) {
      print('Failed to connect: $error');
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('UHST Flutter Demo'),
        ),
        body: Center(
          child: Text('Check the console for UHST status and data updates.'),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // 发送数据示例
            String message = 'Hello, UHST!';
            uhstClient.send(message.codeUnits);
          },
          tooltip: 'Send Data',
          child: Icon(Icons.send),
        ),
      ),
    );
  }

  @override
  void dispose() {
    // 断开连接并释放资源
    uhstClient.disconnect();
    super.dispose();
  }
}

3. 运行应用

确保你的开发环境中已经配置好了必要的权限(比如网络访问权限),然后运行你的Flutter应用。

flutter run

注意事项

  1. API密钥:请确保你替换了YOUR_UHST_API_KEY为你的实际UHST API密钥。
  2. 房间ID:在uhstClient.connect('ROOM_ID')中替换ROOM_ID为实际的房间ID,或者根据你的应用逻辑动态生成房间ID。
  3. 错误处理:在实际应用中,你应该添加更多的错误处理逻辑,以确保应用的健壮性。
  4. 权限:确保你的应用有适当的权限来访问网络。

这个示例展示了如何在Flutter应用中集成UHST插件,并进行基本的数据发送和接收操作。根据你的具体需求,你可能需要进一步定制和扩展这个示例。

回到顶部