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<�0NH�+�,�/�#�'�0�$�(��g@�kj��� �� 23895�A��<=/�� *( +-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�<�վmwX[� �0�5���]��yM!��}/E��|g$�&���8�&~�a?C��_���z��տ�ɝN�D�LJ0�z����|�v,�r�$]���*HJ�$'��xGQ)P�4��TI�=8qc?���)`��N?_U率`���K��U4��8f��� &�
尝试过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
相关产品推荐
相关产品推荐

