Flutter中实现TCP通信的关键步骤与代码示例

 更新时间:2025年09月16日 08:42:02   作者:Dabei  
在移动端开发中,除了常见的 HTTP、MQTT 之外,很多场景需要直接使用 TCP 通信,例如局域网设备控制、实时传输等,本文将介绍在 Flutter/Dart 中实现一个 TCP 客户端的基本过程,并解析关键代码点,需要的朋友可以参考下

引言

在移动端开发中,除了常见的 HTTP、MQTT 之外,很多场景需要直接使用 TCP 通信,例如局域网设备控制、实时传输等。本文将介绍在 Flutter/Dart 中实现一个 TCP 客户端的基本过程,并解析关键代码点。文章同时给出 自动重连心跳保活 的完整示例代码,便于直接落地。

1. 基本思路

  1. 使用 Socket.connect 建立连接
  2. socket 转换为 流(Stream) 进行监听,实时接收消息
  3. 使用 LineSplitter 按行切分消息,避免 TCP 粘包/分包问题(前提:每条消息以 \n 结尾,且内容不含换行)
  4. 加入 超时/心跳自动重连(指数退避 + 抖动)

2. 建立 TCP 连接(明文)

import 'dart:io';
import 'dart:async';
import 'dart:convert';

class TcpClient {
  final String host;
  final int port;
  Socket? _socket;
  StreamSubscription<String>? _subscription;

  TcpClient(this.host, this.port);

  Future<void> connect() async {
    try {
      _socket = await Socket.connect(host, port, timeout: const Duration(seconds: 5));
      print('✅ Connected to: ${_socket!.remoteAddress.address}:${_socket!.remotePort}');

      _subscription = _socket!
          .transform(utf8.decoder)
          .transform(const LineSplitter())
          .listen(_onLine, onError: _onError, onDone: _onDone);
    } catch (e) {
      print('🚫 Connection failed: $e');
      rethrow;
    }
  }

  void _onLine(String line) {
    print('📩 Received line: $line');
  }

  void _onError(Object e, [StackTrace? st]) {
    print('❌ Socket error: $e');
    disconnect();
  }

  void _onDone() {
    print('⚠️ Server closed connection');
    disconnect();
  }

  void send(String message) {
    final s = _socket;
    if (s != null) {
      s.write(message + '\n'); // 每条消息后加换行
      print('📤 Sent: $message');
    }
  }

  void disconnect() {
    _subscription?.cancel();
    _subscription = null;
    _socket?.destroy();
    _socket = null;
    print('🔌 Disconnected');
  }
}

3. 心跳与空闲超时

class HeartbeatManager {
  final void Function() onSendHeartbeat;
  final Duration interval;
  Timer? _timer;

  HeartbeatManager({required this.onSendHeartbeat, this.interval = const Duration(seconds: 30)});

  void start() {
    _timer ??= Timer.periodic(interval, (_) => onSendHeartbeat());
  }

  void stop() {
    _timer?.cancel();
    _timer = null;
  }
}

4. 自动重连(指数退避 + 抖动)

import 'dart:math';

class ReconnectPolicy {
  final Duration minBackoff;
  final Duration maxBackoff;
  int _attempt = 0;
  final Random _rnd = Random();

  ReconnectPolicy({this.minBackoff = const Duration(seconds: 1), this.maxBackoff = const Duration(seconds: 30)});

  Duration nextDelay() {
    final base = minBackoff.inMilliseconds * pow(2, _attempt).toInt();
    final capped = min(base, maxBackoff.inMilliseconds);
    final jitter = (capped * (0.2 * (_rnd.nextDouble() * 2 - 1))).round();
    _attempt = min(_attempt + 1, 10);
    return Duration(milliseconds: max(0, capped + jitter));
  }

  void reset() => _attempt = 0;
}

5. 最佳实践小结

  • 行分隔协议:确保发送端每条消息都以 \n 结尾,且消息体不包含换行
  • 统一编码:收发都用 UTF‑8
  • 心跳保活:15–30 秒 1 次,收不到响应 → 重连
  • 自动重连:指数退避 + 抖动
  • 超时治理:连接超时、请求超时、空闲超时
  • 可观测性:埋点连接时延、失败原因、重连次数、心跳 RTT 等

6. 完整示例代码(可直接运行)

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';

class ReconnectPolicy {
  final Duration minBackoff;
  final Duration maxBackoff;
  int _attempt = 0;
  final Random _rnd = Random();

  ReconnectPolicy({this.minBackoff = const Duration(seconds: 1), this.maxBackoff = const Duration(seconds: 30)});

  Duration nextDelay() {
    final base = minBackoff.inMilliseconds * pow(2, _attempt).toInt();
    final capped = min(base, maxBackoff.inMilliseconds);
    final jitter = (capped * (0.2 * (_rnd.nextDouble() * 2 - 1))).round();
    _attempt = min(_attempt + 1, 10);
    return Duration(milliseconds: max(0, capped + jitter));
  }

  void reset() => _attempt = 0;
}

class HeartbeatManager {
  final void Function() onSendHeartbeat;
  final Duration interval;
  Timer? _timer;

  HeartbeatManager({required this.onSendHeartbeat, this.interval = const Duration(seconds: 30)});

  void start() {
    _timer ??= Timer.periodic(interval, (_) => onSendHeartbeat());
  }

  void stop() {
    _timer?.cancel();
    _timer = null;
  }
}

class RobustLineClient {
  final String host;
  final int port;
  Socket? _socket;
  StreamSubscription<String>? _sub;

  final HeartbeatManager _hb;
  final ReconnectPolicy _policy = ReconnectPolicy();
  Timer? _idleTimer;

  RobustLineClient({required this.host, required this.port})
      : _hb = HeartbeatManager(onSendHeartbeat: () {/* later bound */}, interval: const Duration(seconds: 20));

  Future<void> start() async {
    await _connect();
  }

  Future<void> _connect() async {
    try {
      _socket = await Socket.connect(host, port, timeout: const Duration(seconds: 5));
      print('✅ connected');
      _policy.reset();
      _hb.start();

      _sub = _socket!
          .transform(utf8.decoder)
          .transform(const LineSplitter())
          .listen(_onLine, onError: _onError, onDone: _onDone);

      // 心跳绑定到 send
      _hb.onSendHeartbeat.call = () => send('ping');

      _resetIdleTimeout();
    } catch (e) {
      print('🚫 connect failed: $e');
      await _scheduleReconnect();
    }
  }

  void _onLine(String line) {
    _resetIdleTimeout();
    print('📩 $line');
  }

  void _onError(Object e, [StackTrace? st]) {
    print('❌ $e');
    _teardown();
    _scheduleReconnect();
  }

  void _onDone() {
    print('⚠️ closed by server');
    _teardown();
    _scheduleReconnect();
  }

  void _teardown() {
    _idleTimer?.cancel();
    _idleTimer = null;
    _hb.stop();
    _sub?.cancel();
    _sub = null;
    _socket?.destroy();
    _socket = null;
  }

  Future<void> _scheduleReconnect() async {
    final delay = _policy.nextDelay();
    print('⏳ reconnect in ${delay.inMilliseconds} ms');
    await Future.delayed(delay);
    await _connect();
  }

  void _resetIdleTimeout() {
    _idleTimer?.cancel();
    _idleTimer = Timer(const Duration(seconds: 60), () {
      print('⏰ idle timeout -> reconnect');
      _teardown();
      _scheduleReconnect();
    });
  }

  void send(String message) {
    _socket?.write(message + '\n');
  }
}

以上就是Flutter中实现TCP通信的关键步骤与代码示例的详细内容,更多关于Flutter实现TCP通信的资料请关注脚本之家其它相关文章!

相关文章

  • Android Jetpack架构中ViewModel接口暴露的不合理探究

    Android Jetpack架构中ViewModel接口暴露的不合理探究

    这篇文章主要介绍了Android Jetpack架构组件 ViewModel详解,ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在,ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。感兴趣可以来学习一下
    2022-07-07
  • 分享40条Android开发的优化建议

    分享40条Android开发的优化建议

    这篇文章主要为大家详细介绍了40条Android开发的优化建议,帮助大家更好的开发Android项目,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • Android项目开发之UI设计器

    Android项目开发之UI设计器

    这篇文章主要为大家详细介绍了Android项目开发之UI设计器,具有一定的实用性和参考价值,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Android中利用C++处理Bitmap对象的实现方法

    Android中利用C++处理Bitmap对象的实现方法

    下面小编就为大家带来一篇Android中利用C++处理Bitmap对象的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • Art 虚拟机系列Heap内存模型分配策略详解

    Art 虚拟机系列Heap内存模型分配策略详解

    这篇文章主要为大家介绍了Art 虚拟机系列Heap内存模型分配策略详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Android跟随手指移动的控件demo实例

    Android跟随手指移动的控件demo实例

    大家好,本篇文章主要讲的是Android跟随手指移动的控件demo实例,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • Kotlin + Flow 实现Android 应用初始化任务启动库

    Kotlin + Flow 实现Android 应用初始化任务启动库

    这篇文章主要介绍了Kotlin + Flow 实现Android 应用初始化任务启动库的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下
    2021-03-03
  • Android实现关机后数据不会丢失问题

    Android实现关机后数据不会丢失问题

    这篇文章主要介绍了Android实现关机后数据不会丢失问题,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • Android中ListView + CheckBox实现单选、多选效果

    Android中ListView + CheckBox实现单选、多选效果

    这篇文章主要介绍了Android中ListView + CheckBox实现单选、多选效果,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-02-02
  • android实现滑动解锁

    android实现滑动解锁

    这篇文章主要为大家详细介绍了android实现滑动解锁,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04

最新评论