如何在Java与Dart(Flutter) Socket间传输Unicode文本?
我尝试在Java服务器与Dart(Flutter)客户端之间交换字符串,要求支持完整Unicode(如utf8mb4_unicode_ci级别)。
Java端IO流配置
使用以下方式打开IO流,通过inStream.readLine()和outStream.println()读写,所有数据以Java String对象处理:
outStream = new PrintWriter(clientSocket.getOutputStream(), true, StandardCharsets.UTF_8); inStream = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));
Dart(Flutter)客户端IO流配置
Socket连接与流处理如下,读取时通过缓冲区处理拆分的大数据包,通过socket.writeln(query)写入,数据以Dart String对象处理:
Socket socket = Socket.connect(url, port); Stream<String>? stream = socket?.asBroadcastStream().map(String.fromCharCodes);
读取逻辑:
StringBuffer responseBuffer = StringBuffer(); await for (String packet in stream!) { responseBuffer.write(packet); if (packet.contains('_')) { break; } }
当前问题
传输äöüß(德语字符)或表情等非ASCII字符时,接收端显示为?或方框问号,需要调整两端配置以确保均用UTF-8处理字符串。
乱码核心原因是Dart端未明确指定UTF-8编码进行字节转换,默认编码与Java端的UTF-8不匹配,以下是具体修改:
1. Dart客户端发送逻辑修改
替换默认的socket.writeln(query),明确用UTF-8编码字符串后发送(需导入dart:convert):
import 'dart:convert'; // ... // 替换socket.writeln(query)为: socket.add(utf8.encode('$query\n'));
解释:writeln默认使用系统编码(如Windows上为GBK),会将Unicode字符转成错误的字节;utf8.encode直接将字符串转为UTF-8字节数组,加上\n换行符匹配Java端readLine()的读取规则。
2. Dart客户端读取逻辑修改
将字节流转字符串的方式改为utf8.decoder处理,确保多字节Unicode字符被正确解码:
import 'dart:convert'; import 'dart:io'; // ... Socket socket = await Socket.connect(url, port); // 替换原stream创建逻辑 Stream<String> stream = socket.asBroadcastStream().transform(utf8.decoder);
解释:原map(String.fromCharCodes)会将每个字节单独解析为Unicode码点,而UTF-8是多字节编码,拆分的数据包会导致单个字符被拆成多个无效码点;utf8.decoder会自动处理跨数据包的多字节字符,保证解码正确性。
3. 验证Java端配置(无需修改)
Java端已明确指定StandardCharsets.UTF_8初始化PrintWriter和InputStreamReader,配置正确,无需调整。
内容的提问来源于stack exchange,提问作者Konstanius EU

