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

Android向Python服务器发送非ASCII字符数据时末尾字节丢失求助

解决UTF-8字符导致Socket传输数据截断的问题

问题根源

你的核心问题是混淆了字符数和UTF-8字节数:

  • Android端发送的长度是字符串的字符数量(比如é算1个字符),但UTF-8编码中这类非ASCII字符占2~4个字节;
  • Python服务器用这个字符数去读取字节,实际需要读取的字节数远大于字符数,导致只读到部分数据,剩余字节留在缓冲区,表现为JSON末尾截断。

修复方案

1. Android客户端修改:发送字节长度而非字符长度

必须先将字符串编码为UTF-8字节数组,计算字节数组的长度作为传输头部,再发送头部和字节数据:

private void send(String sendingStr) {
    try {
        // 定义与服务器一致的头部长度,比如4位
        final int HEADER_LENGTH = 4;
        // 将字符串转为UTF-8字节数组
        byte[] dataBytes = sendingStr.getBytes(StandardCharsets.UTF_8);
        // 把字节长度格式化为固定长度的字符串(补零填充)
        String lengthHeader = String.format("%0" + HEADER_LENGTH + "d", dataBytes.length);
        
        OutputStream outputStream = socket.getOutputStream();
        // 先发送头部(编码为UTF-8字节)
        outputStream.write(lengthHeader.getBytes(StandardCharsets.UTF_8));
        // 再发送实际数据字节
        outputStream.write(dataBytes);
        outputStream.flush();

        Log.d("Result", "已发送 " + dataBytes.length + " 字节");
    } catch (Exception e) {
        Log.e("Exception", e.toString());
    }
}

2. Python服务器修改:按字节长度读取数据

服务器需要先读取固定长度的头部,解析出实际字节数,再读取对应长度的字节数据,最后解码为字符串:

HEADER_LENGTH = 4  # 与客户端保持一致

def recv_all(sock, total_length):
    """确保读取到指定长度的字节数据,处理网络分段传输"""
    received_data = b''
    while len(received_data) < total_length:
        chunk = sock.recv(total_length - len(received_data))
        if not chunk:
            return None  # 连接已断开
        received_data += chunk
    return received_data

while True:
    client_socket, client_address_port = server_socket.accept()
    print(f"{client_address_port} 已连接")

    # 读取长度头部
    header_bytes = recv_all(client_socket, HEADER_LENGTH)
    if not header_bytes:
        continue
    byte_length = int(header_bytes.decode('utf-8'))
    
    # 读取实际数据字节并解码
    activity_data = recv_all(client_socket, byte_length)
    if not activity_data:
        continue
    activity_name = activity_data.decode('utf-8')
    print(f"收到: {byte_length} 字节 - {activity_name}")

    if activity_name:
        # 处理第二个数据块
        header_bytes = recv_all(client_socket, HEADER_LENGTH)
        if not header_bytes:
            continue
        byte_length = int(header_bytes.decode('utf-8'))
        
        data_bytes = recv_all(client_socket, byte_length)
        if not data_bytes:
            continue
        data_string = data_bytes.decode('utf-8')
        print(f"收到: {byte_length} 字节 - {data_string}")

关键注意事项

  • 客户端和服务器的HEADER_LENGTH必须严格一致,建议设为4或8(足够覆盖大部分数据长度);
  • 永远不要用字符串的字符数作为传输长度,必须基于UTF-8编码后的字节数计算;
  • 使用recv_all这类封装函数处理网络传输,避免因网络分段导致的不完整读取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 23:10:43