You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter TCP Socket向Python发送SSID/PSK字符串失败求助

Flutter TCP Socket 传输SSID/PSK到Python服务端问题解决

问题根源

Flutter客户端问题

  • 发送数据后立即断开连接,可能导致数据未完全发送就终止连接,服务端无法接收完整数据。
  • Future.delayed未使用await,导致重连操作会立刻执行,连接状态混乱。
  • 每次发送单个字段就断开重连,不符合TCP长连接的使用逻辑,也会导致服务端的接收逻辑不匹配。

Python服务端问题

  • 每次客户端连接后连续调用三次recv,但客户端每次仅发送一个字段,多余的recv会阻塞程序,等待不存在的数据。
  • 未处理客户端断开连接的情况,recv返回空字节时未关闭套接字,导致资源浪费。

修正后的代码

Flutter客户端代码

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

class UsersPage extends StatefulWidget {
  @override
  _UsersPageState createState() => _UsersPageState();
}

class _UsersPageState extends State<UsersPage> {
  TcpSocketConnection socketConnection = TcpSocketConnection("my_ip", 9000); 
  String message = "";
  String ssid = "";
  String psk = "";

  @override
  void initState() {
    super.initState();
    startConnection();
  }

  void messageReceived(String msg) {
    setState(() {
      message = msg;
    });
  }

  void startConnection() async {
    socketConnection.enableConsolePrint(true);
    if (await socketConnection.canConnect(2000, attempts: 3)) {
      await socketConnection.connect(2000, messageReceived, attempts: 3);
    }
  }

  // 统一发送数据逻辑
  void sendData(String data) async {
    if (socketConnection.isConnected()) {
      await socketConnection.sendMessage(data);
      print("已发送: $data");
    } else {
      print("连接未建立,尝试重连...");
      await startConnection();
      if (socketConnection.isConnected()) {
        await socketConnection.sendMessage(data);
        print("重连后已发送: $data");
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          appBar: AppBar(title: const Text("WiFi配置")),
          body: Center(
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                  TextField(
                    decoration: InputDecoration(
                      hintText: '输入WiFi名称',
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(20.0)),
                      ),
                      enabledBorder: OutlineInputBorder(
                        borderSide:
                            BorderSide(color: Colors.blueAccent, width: 1.0),
                        borderRadius: BorderRadius.all(Radius.circular(20.0)),
                      ),
                      contentPadding:
                          EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
                      prefixIcon: Icon(Icons.wifi),
                    ),
                    onChanged: (text) {
                      setState(() {
                        ssid = text;
                      });
                    },
                  ),
                  SizedBox(height: 30),
                  TextField(
                    decoration: InputDecoration(
                      hintText: '输入WiFi密码',
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(20.0)),
                      ),
                      enabledBorder: OutlineInputBorder(
                        borderSide:
                            BorderSide(color: Colors.blueAccent, width: 1.0),
                        borderRadius: BorderRadius.all(Radius.circular(20.0)),
                      ),
                      contentPadding:
                          EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
                      prefixIcon: Icon(Icons.lock),
                    ),
                    onChanged: (text) {
                      setState(() {
                        psk = text;
                      });
                    },
                  ),
                  SizedBox(height: 30),
                  ElevatedButton(
                    onPressed: () => sendData(ssid),
                    child: Text('发送SSID'),
                  ),
                  SizedBox(height: 30),
                  ElevatedButton(
                    onPressed: () => sendData(psk),
                    child: Text('发送PSK'),
                  ),
                  SizedBox(height: 30),
                  ElevatedButton(
                    onPressed: () {
                      if (socketConnection.isConnected()) {
                        socketConnection.disconnect();
                        setState(() => message = "已断开连接");
                      }
                    },
                    child: Text('断开连接'),
                  ),
                  SizedBox(height: 20),
                  Text("服务端回复: $message")
                ]),
              ),
            ),
        ));
  }
}

改动说明

  • 新增sendData方法,统一处理数据发送逻辑,先检查连接状态,未连接则尝试重连后发送。
  • 移除每次发送后的断开重连逻辑,保持长连接,避免连接频繁建立/销毁。
  • 添加页面布局优化,增加连接状态提示。
  • 修正异步逻辑错误,确保重连操作等待完成后再执行发送。

Python服务端代码

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0", 9000))
s.listen(5)
print("服务端已启动,等待客户端连接...")

while True:
    clientsocket, address = s.accept()
    print(f"来自 {address} 的连接已建立.")
    
    try:
        while True:
            data = clientsocket.recv(1024)
            if not data:
                # 客户端断开连接
                print(f"客户端 {address} 已断开")
                break
            received_data = data.decode().strip()
            print(f"收到数据: {received_data}")
            # 可选:回复客户端确认接收
            clientsocket.sendall(f"已收到: {received_data}".encode())
    except Exception as e:
        print(f"连接异常: {e}")
    finally:
        clientsocket.close()

改动说明

  • 改为循环接收数据,直到客户端断开连接,匹配长连接场景。
  • 处理客户端断开的情况,关闭套接字并跳出循环。
  • 添加异常捕获,避免连接异常导致服务端崩溃。
  • 增加回复客户端的逻辑,方便客户端确认数据已送达。

进阶优化建议

如果需要同时发送SSID和PSK,建议使用JSON格式一次性传输,避免多次发送:

Flutter端发送JSON

import 'dart:convert';

// 添加发送完整配置的按钮和方法
void sendWifiConfig() async {
  if (ssid.isNotEmpty && psk.isNotEmpty) {
    final config = jsonEncode({"ssid": ssid, "psk": psk});
    await sendData(config);
  }
}

Python端解析JSON

import json

# 在接收循环中解析JSON
received_data = data.decode().strip()
try:
    config = json.loads(received_data)
    print(f"SSID: {config['ssid']}, PSK: {config['psk']}")
except json.JSONDecodeError:
    print(f"非JSON格式数据: {received_data}")

内容的提问来源于stack exchange,提问作者Mesut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 19:25:43