弱水八千 發表於 2025-9-16 08:42:02

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

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>引言</li><li>1. 基本思路</li><li>2. 建立 TCP 连接(明文)</li><li>3. 心跳与空闲超时</li><li>4. 自动重连(指数退避 + 抖动)</li><li>5. 最佳实践小结</li><li>6. 完整示例代码(可直接运行)</li></ul></div><p class="maodian"></p><h2>引言</h2>
<p>在移动端开发中,除了常见的 HTTP、MQTT 之外,很多场景需要直接使用 <strong>TCP 通信</strong>,例如局域网设备控制、实时传输等。本文将介绍在 Flutter/Dart 中实现一个 <strong>TCP 客户端</strong>的基本过程,并解析关键代码点。文章同时给出 <strong>自动重连</strong> 与 <strong>心跳保活</strong> 的完整示例代码,便于直接落地。</p>
<p class="maodian"></p><h2>1. 基本思路</h2>
<ol><li>使用 <code>Socket.connect</code> 建立连接</li><li>将 <code>socket</code> 转换为 <strong>流(Stream)</strong> 进行监听,实时接收消息</li><li>使用 <code>LineSplitter</code> 按行切分消息,避免 TCP 粘包/分包问题(前提:每条消息以 <code>\n</code> 结尾,且内容不含换行)</li><li>加入 <strong>超时/心跳</strong> 与 <strong>自动重连(指数退避 + 抖动)</strong></li></ol>
<p class="maodian"></p><h2>2. 建立 TCP 连接(明文)</h2>
<div class="jb51code"><pre class="brush:java;">import 'dart:io';
import 'dart:async';
import 'dart:convert';

class TcpClient {
final String host;
final int port;
Socket? _socket;
StreamSubscription&lt;String&gt;? _subscription;

TcpClient(this.host, this.port);

Future&lt;void&gt; 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, ) {
    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');
}
}
</pre></div>
<p class="maodian"></p><h2>3. 心跳与空闲超时</h2>
<div class="jb51code"><pre class="brush:java;">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, (_) =&gt; onSendHeartbeat());
}

void stop() {
    _timer?.cancel();
    _timer = null;
}
}
</pre></div>
<p class="maodian"></p><h2>4. 自动重连(指数退避 + 抖动)</h2>
<div class="jb51code"><pre class="brush:java;">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() =&gt; _attempt = 0;
}
</pre></div>
<p class="maodian"></p><h2>5. 最佳实践小结</h2>
<ul><li><strong>行分隔协议</strong>:确保发送端每条消息都以 <code>\n</code> 结尾,且消息体不包含换行</li><li><strong>统一编码</strong>:收发都用 UTF‑8</li><li><strong>心跳保活</strong>:15&ndash;30 秒 1 次,收不到响应 &rarr; 重连</li><li><strong>自动重连</strong>:指数退避 + 抖动</li><li><strong>超时治理</strong>:连接超时、请求超时、空闲超时</li><li><strong>可观测性</strong>:埋点连接时延、失败原因、重连次数、心跳 RTT 等</li></ul>
<p class="maodian"></p><h2>6. 完整示例代码(可直接运行)</h2>
<div class="jb51code"><pre class="brush:java;">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() =&gt; _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, (_) =&gt; onSendHeartbeat());
}

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

class RobustLineClient {
final String host;
final int port;
Socket? _socket;
StreamSubscription&lt;String&gt;? _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&lt;void&gt; start() async {
    await _connect();
}

Future&lt;void&gt; _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 = () =&gt; send('ping');

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

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

void _onError(Object e, ) {
    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&lt;void&gt; _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 -&gt; reconnect');
      _teardown();
      _scheduleReconnect();
    });
}

void send(String message) {
    _socket?.write(message + '\n');
}
}
</pre></div>
<p>以上就是Flutter中实现TCP通信的关键步骤与代码示例的详细内容,更多关于Flutter实现TCP通信的资料请关注琼殿技术社区其它相关文章!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Flutter web bridge 通信总结分析详解</li><li>Flutter与WebView通信方案示例详解</li><li>Android开发之Flutter与webview通信桥梁实现</li><li>Flutter使用JsBridge方式处理Webview与H5通信的方法</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Flutter中实现TCP通信的关键步骤与代码示例