Flutter WebSocket多数据发送时数据流混叠问题求助
解决WebSocket连续发送数据混叠的简单方案
你的核心问题是连续发送的多条消息在接收端被合并,导致无法区分。之前用ASCII空字符没解决,大概率是因为空字符可能出现在消息内容里,或者接收端的拆分逻辑没处理好。下面给几个简单高效的解决办法:
方案1:用JSON序列化每条消息(最易实现)
把每条消息封装成独立的JSON对象,再用换行符分隔(确保每条JSON单独占一行),接收端按行拆分后逐个解析JSON,就能精准区分不同类型的消息。
发送代码修改:
import 'dart:convert'; void sendData(CurrentUser user) { // 发送用户名称 socket?.writeln(jsonEncode({ 'type': 'name', 'value': user.name })); // 发送对象数量 socket?.writeln(jsonEncode({ 'type': 'amount', 'value': user.objects.length })); // 发送每个对象信息 for(var object in user.objects) { socket?.writeln(jsonEncode({ 'type': 'object', 'value': 'ObjectInfoHere' // 替换成你的对象实际数据 })); } }
接收端处理逻辑示例:
socket?.listen((data) { // 按换行拆分所有收到的消息 List<String> messages = data.toString().split('\n'); for (String msg in messages) { if (msg.isEmpty) continue; // 解析JSON Map<String, dynamic> parsed = jsonDecode(msg); switch(parsed['type']) { case 'name': // 处理名称 break; case 'amount': // 处理数量 break; case 'object': // 处理对象 break; } } });
方案2:给每条消息加长度前缀(最可靠)
先发送消息的字节长度(用固定长度的二进制格式,比如4字节大端整数),再发送消息内容。接收端先读取长度,再读取对应长度的字节,完全不会出现混叠问题。
发送代码修改:
import 'dart:convert'; import 'dart:typed_data'; void sendData(CurrentUser user) { // 发送名称消息 _sendMessage(socket, 'name|${user.name}'); // 发送数量消息 _sendMessage(socket, 'amount|${user.objects.length}'); // 发送每个对象消息 for(var object in user.objects) { _sendMessage(socket, 'object|ObjectInfoHere'); } } // 封装发送逻辑:先发长度,再发内容 void _sendMessage(WebSocket? socket, String content) { if (socket == null) return; List<int> contentBytes = utf8.encode(content); // 将长度转换成4字节大端格式 Uint8List lengthBytes = Uint8List(4); ByteData byteData = lengthBytes.buffer.asByteData(); byteData.setUint32(0, contentBytes.length, Endian.big); // 先发送长度,再发送内容 socket.add(lengthBytes); socket.add(contentBytes); }
接收端处理逻辑示例:
List<int> buffer = []; socket?.listen((data) { buffer.addAll(data); // 循环处理缓冲区中的完整消息 while (buffer.length >= 4) { // 先读取4字节的长度 ByteData byteData = Uint8List.fromList(buffer.sublist(0,4)).buffer.asByteData(); int msgLength = byteData.getUint32(0, Endian.big); // 如果缓冲区中的数据足够一条消息 if (buffer.length >= 4 + msgLength) { // 提取消息内容 List<int> msgBytes = buffer.sublist(4, 4 + msgLength); String msg = utf8.decode(msgBytes); // 处理消息(比如按|拆分类型和数据) List<String> parts = msg.split('|'); switch(parts[0]) { case 'name': // 处理名称 break; case 'amount': // 处理数量 break; case 'object': // 处理对象 break; } // 移除已处理的部分 buffer = buffer.sublist(4 + msgLength); } else { // 数据不够,等待下一次接收 break; } } });
方案3:使用唯一分隔符(适合内容可控场景)
选一个绝对不会出现在消息内容里的字符串作为分隔符(比如###MESSAGE_END###),每条消息末尾加上这个分隔符,接收端收到数据后按分隔符拆分即可。
发送代码修改:
void sendData(CurrentUser user) { const separator = '###MESSAGE_END###'; socket?.write('name|${user.name}$separator'); socket?.write('amount|${user.objects.length}$separator'); for(var object in user.objects) { socket?.write('object|ObjectInfoHere$separator'); } }
接收端处理逻辑示例:
String buffer = ''; socket?.listen((data) { buffer += data.toString(); const separator = '###MESSAGE_END###'; // 拆分所有完整消息 List<String> messages = buffer.split(separator); // 最后一个元素可能是不完整的消息,放回缓冲区 buffer = messages.removeLast(); // 处理每条完整消息 for(String msg in messages) { if (msg.isEmpty) continue; List<String> parts = msg.split('|'); switch(parts[0]) { case 'name': // 处理名称 break; case 'amount': // 处理数量 break; case 'object': // 处理对象 break; } } });
为什么之前的空字符没用?
ASCII空字符\u0000可能出现在某些字符串内容里(比如用户名称包含特殊字符时),或者接收端的拆分逻辑没有正确处理缓冲区中连续的空字符,导致拆分失败。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

