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

TCP代理MySQL时客户端数据输出乱码问题求助

问题

基于Boost Asio实现TCP代理MySQL功能,核心代码如下:

// std:string _sql_statement;
// char _client_data[max_data_length];
// size_t bytes_transferred;

void tcp_proxy::Bridge::handle_read_fclient(const error_code& error, const size_t & bytes_transferred)
{

    if (!error) {
        
        asio::async_write(*_upstream_socket.get(),
            asio::buffer(_client_data, bytes_transferred),
            boost::bind(&Bridge::handle_write_tserver,
                shared_from_this(),
                asio::placeholders::error)
        );
        
        _sql_statement.append(_client_data, bytes_transferred);
        std::cout << _sql_statement << "\n";
    }
    else {
        stop();
    }
}

运行MySQL客户端发送SQL查询时,输出乱码:

����=9漢     �\�gOx� �u%e��A ��
��jxt�6����                               �bc ���z�
           �-x��w&lt;�0NH�+�,�/�#�'�0�$�(��g@�kj���        ��
23895�A��&lt;=/��

*(

+-3GEA1�����Ȩf� ��b�_�Epx����D�47�~�;%/x��C)�Q���D3     ���n�]�B�brU�N�ݘ%_\�
                                                                            7F�e����
                                                                                    u��ED�Ϳ�T�Q����XyȀt�xb8��� ����������'�Zm�V엇DT��!»
                                                                                                                                       ����@��2��     Nd۠;��̭�1�t5QtU�M�`�B�&lt;�վmwX[�
�0�5���]��yM!��}/E��|g$�&amp;���8�&amp;~�a?C��_���z��տ�ɝN�D�LJ0�z����|�v,�r�$]���*HJ�$'��xGQ)P�4��TI�=8qc?���)`��N?_U率`���K��U4��8f���  &amp;�

尝试过printf输出,依旧无效。

解决提示

  • MySQL客户端与服务端的通信采用二进制协议,并非明文文本流。直接把收到的所有字节当作字符串输出,会包含协议头、认证数据、握手信息等二进制内容,必然出现乱码。
  • 只有当数据包类型为COM_QUERY(命令码为0x03)时,数据包的payload部分才是明文SQL语句。需要先解析协议结构,过滤掉非SQL的二进制内容。
  • MySQL数据包通用头部规则:前3字节是数据包长度(小端字节序),第4字节是序列号。跳过头部后,检查第5字节是否为0x03(COM_QUERY命令),如果是,从第5字节开始的内容才是SQL语句。

代码修改示例

调整handle_read_fclient中的数据处理逻辑,只提取COM_QUERY对应的SQL内容:

void tcp_proxy::Bridge::handle_read_fclient(const error_code& error, const size_t & bytes_transferred)
{
    if (!error) {
        asio::async_write(*_upstream_socket.get(),
            asio::buffer(_client_data, bytes_transferred),
            boost::bind(&Bridge::handle_write_tserver,
                shared_from_this(),
                asio::placeholders::error)
        );

        // 解析MySQL数据包头部,提取SQL查询内容
        if (bytes_transferred >= 5) { // 头部4字节 + 至少1字节命令码
            // 计算数据包长度(小端字节序)
            uint32_t packet_len = (_client_data[0] & 0xFF) | 
                                 ((_client_data[1] & 0xFF) << 8) | 
                                 ((_client_data[2] & 0xFF) << 16);

            // 检查是否为COM_QUERY命令(0x03),且数据长度匹配
            if (_client_data[4] == 0x03 && (bytes_transferred - 4) == packet_len) {
                // 从第5字节开始是SQL语句
                std::string sql(_client_data + 4, bytes_transferred - 4);
                std::cout << "收到SQL查询:" << sql << "\n";
            }
        }
    }
    else {
        stop();
    }
}
  • 补充:MySQL协议还有其他命令类型(如COM_STMT_PREPARE、COM_PING等),如果需要解析更多场景,需要参考完整的MySQL协议规范,区分不同命令包的结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 14:54:53