在移动应用开发中,TCP 协议因其可靠的面向连接特性,广泛应用于实时通讯、设备控制、数据同步等场景。Flutter 作为跨平台框架,通过 Dart 语言的dart:io库原生支持 TCP 编程,无需依赖第三方插件即可实现完整的客户端 / 服务器交互。
一、核心技术栈与原理
1.1 关键依赖库
- dart:io:提供Socket(客户端)和ServerSocket(服务器)类,是 TCP 通讯的核心 API
- dart:convert:用于 UTF-8 数据编码解码,处理二进制数据与字符串的转换
- dart:async:支持异步编程(async/await),处理 TCP 连接、数据收发等异步操作
- Flutter UI 组件:StatefulWidget(状态管理)、TextField(输入)、ListView(消息展示)等
1.2 TCP 通讯核心原理
- 客户端流程:建立连接(Socket.connect)→ 发送数据(socket.write)→ 监听接收数据(socket.listen)→ 断开连接(socket.close)
- 服务器流程:绑定端口(ServerSocket.bind)→ 监听客户端连接(await for)→ 处理客户端消息(handleClient)→ 回复数据
- 状态管理:通过setState更新连接状态、消息列表等 UI 展示
二、完整实现:Flutter TCP 客户端
2.1 项目结构与核心变量
客户端采用StatefulWidget管理动态状态,核心变量包括:
dart
Socket? _socket; // TCP连接对象
bool _isConnected = false; // 连接状态标记
String _status = '未连接'; // 状态文本
Listmessages = []; // 消息历史列表
// 输入控制器(IP、端口、消息)
final TextEditingController _ipController = TextEditingController(text: '127.0.0.1');
final TextEditingController _portController = TextEditingController(text: '8080');
final TextEditingController _messageController = TextEditingController();
2.2 核心功能实现
(1)连接 TCP 服务器
dart
/// 连接到TCP服务器
///
/// 功能:
/// 1. 更新UI显示连接中状态
/// 2. 尝试与指定IP和端口的服务器建立TCP连接
/// 3. 连接成功后更新UI状态并开始监听服务器消息
/// 4. 处理连接错误和异常
///
/// 返回值:
/// - Future<void>: 异步操作,无返回值
Future<void> _connectToServer() async {
try {
// 更新UI状态为连接中
setState(() {
_status = '连接中...';
});
// 建立TCP连接
// 参数说明:
// - host: 服务器IP地址,从输入框获取
// - port: 服务器端口,从输入框获取并转换为整数
// - timeout: 连接超时时间,设置为5秒
_socket = await Socket.connect(
_ipController.text, // 服务器IP地址
int.parse(_portController.text), // 服务器端口
timeout: const Duration(seconds: 5), // 连接超时时间
);
// 连接成功,更新UI状态
setState(() {
_isConnected = true; // 设置连接状态为已连接
_status = '已连接'; // 更新状态文本
_messages.add('已连接到服务器'); // 添加连接成功消息
});
// 开始监听Socket事件
_socket!.listen(
// 收到数据时的回调函数
(List<int> data) {
// 将接收到的二进制数据转换为字符串
final message = utf8.decode(data);
// 更新UI,添加服务器消息
setState(() {
_messages.add('服务器: $message');
});
},
// 发生错误时的回调函数
onError: (error) {
// 更新UI状态为错误
setState(() {
_isConnected = false; // 设置连接状态为未连接
_status = '连接错误'; // 更新状态文本
_messages.add('错误: $error'); // 添加错误消息
});
// 关闭Socket连接
_socket?.close();
},
// 连接关闭时的回调函数
onDone: () {
// 更新UI状态为连接关闭
setState(() {
_isConnected = false; // 设置连接状态为未连接
_status = '连接关闭'; // 更新状态文本
_messages.add('连接已关闭'); // 添加连接关闭消息
});
// 关闭Socket连接
_socket?.close();
},
);
} catch (e) {
// 捕获连接过程中的异常
setState(() {
_status = '连接失败'; // 更新状态文本为连接失败
_messages.add('错误: $e'); // 添加错误消息
});
}
}
(2)断开连接与发送消息
dart
// 断开连接
/// 断开与TCP服务器的连接
///
/// 功能:
/// 1. 关闭当前的Socket连接
/// 2. 更新UI状态为未连接
/// 3. 添加断开连接消息到消息列表
void _disconnectFromServer() {
// 关闭Socket连接
_socket?.close();
// 更新UI状态
setState(() {
_isConnected = false; // 设置连接状态为未连接
_status = '未连接'; // 更新状态文本
_messages.add('已断开连接'); // 添加断开连接消息
});
}
/// 发送消息到TCP服务器
///
/// 功能:
/// 1. 检查当前是否已连接到服务器
/// 2. 获取输入框中的消息内容
/// 3. 发送消息到服务器(添加换行符便于服务器处理)
/// 4. 更新UI,添加发送的消息到消息列表
/// 5. 清空消息输入框
void _sendMessage() {
// 检查连接状态
if (_socket != null && _isConnected) {
// 获取输入的消息
final message = _messageController.text;
// 发送消息到服务器,添加换行符便于服务器处理
_socket!.write('$message\n');
// 更新UI,添加发送的消息
setState(() {
_messages.add('客户端: $message'); // 添加客户端消息
_messageController.clear(); // 清空输入框
});
}
}
三、配套 TCP 服务器实现(Dart)
为了测试客户端,我们用 Dart 编写一个简单的 TCP 服务器,监听 8080 端口:
dart
import 'dart:io'; // 提供Socket和网络功能
import 'dart:core'; // 提供Dart核心功能
/// TCP服务器示例
///
/// 功能:
/// 1. 监听本地8080端口,接收TCP客户端连接
/// 2. 处理客户端发送的消息,解码并打印
/// 3. 回复客户端消息,确认收到
/// 4. 处理连接错误和异常
/// 5. 提供详细的日志输出,便于调试
///
/// 技术要点:
/// - 使用dart:io库的ServerSocket类创建TCP服务器
/// - 使用await for循环监听客户端连接
/// - 使用Socket.listen()方法监听Socket事件
/// - 使用try-catch处理异常
/// - 使用DateTime.now()添加时间戳日志
/// 服务器主函数
/// 功能:启动TCP服务器,监听客户端连接
///
void main() async {
try {
// 绑定服务器地址和端口
// 参数说明:
// - address: 服务器地址,'127.0.0.1'表示本地地址
// - port: 服务器端口,8080是常用测试端口
// 返回值:
// - ServerSocket实例,用于监听客户端连接
final server = await ServerSocket.bind('127.0.0.1', 8080);
// 持续监听客户端连接
// await for循环会自动处理异步流,每次有新连接时执行循环体
await for (var socket in server) {
// 为每个客户端创建一个处理函数
handleClient(socket);
}
} catch (e) {
// 捕获启动服务器时的错误
print('${DateTime.now()} - 启动服务器时出错: $e');
}
}
/// 处理客户端连接
/// 功能:处理单个客户端的消息收发和连接管理
///
/// 参数:
/// - socket: Socket对象,表示与客户端的连接
///
/// 执行流程:
/// 1. 获取客户端地址和端口信息
/// 2. 打印客户端连接信息
/// 3. 监听Socket事件(数据接收、错误、关闭)
/// 4. 处理接收到的消息,解码并回复
/// 5. 处理连接错误和异常
/// 6. 处理连接关闭事件
void handleClient(Socket socket) {
// 构建客户端地址和端口的字符串表示
final clientAddr = '${socket.remoteAddress.address}:${socket.remotePort}';
// 监听Socket事件
socket.listen(
// 收到数据时的回调函数
// 参数:
// - data: List<int>类型,表示接收到的二进制数据
(List<int> data) {
try {
// 尝试将二进制数据转换为字符串
// 使用String.fromCharCodes()方法解码,然后去除首尾空白字符
final message = String.fromCharCodes(data, 0, data.length).trim();
// 构建回复消息,添加换行符便于客户端处理
final response = '服务器收到: $message\n';
// 发送回复给客户端
socket.write(response);
} catch (e) {
// 构建错误回复消息
final response = '解码错误\n';
// 发送错误回复给客户端
socket.write(response);
}
},
// 发生错误时的回调函数
// 参数:
// - error: 错误对象,表示发生的错误
onError: (error) {
// 打印处理客户端错误的日志
print('${DateTime.now()} - 处理客户端 $clientAddr 时出错: $error');
// 关闭客户端连接
socket.close();
},
// 连接关闭时的回调函数
onDone: () {
// 打印客户端连接关闭的日志
print('${DateTime.now()} - 客户端 $clientAddr 连接已关闭');
// 关闭客户端连接
socket.close();
},
);
}
四、实战测试步骤
4.1 运行服务器
- 创建server.dart文件,复制上述服务器代码
- 终端执行:dart server.dart,启动服务器(显示 "服务器启动,监听 127.0.0.1:8080" 即为成功)
4.2 运行 Flutter 客户端
- 创建 Flutter 项目:flutter create tcp_demo
- 替换lib/main.dart为客户端代码
- 运行项目:flutter run(支持模拟器或真机)
- 操作流程:
- 输入服务器 IP(本地测试用127.0.0.1)和端口(8080)
- 点击 "连接",状态变为 "已连接"
- 输入消息,点击 "发送",即可与服务器双向通讯
4.3 预期效果
- 客户端发送消息后,消息列表显示 "客户端:消息内容"
- 服务器收到消息后,终端打印日志,并回复 "服务器收到:消息内容"
- 客户端接收回复后,消息列表显示 "服务器:回复内容"
- 断开连接后,双方均会收到连接关闭通知
Flutter 通过 Dart 的dart:io库提供了简洁强大的 TCP 通讯能力,无需依赖第三方插件即可实现客户端与服务器的双向通讯。无论是实时聊天、设备控制还是数据同步场景,Flutter TCP 通讯都能满足需求。