MySQL协议解析及C/C++代码实现

MySQL 常用于许多知名网站,包括 Facebook、Google、Twitter 和 YouTube等等。它于 1995 年首次发布。MySQL 是用 C 和 C++ 编写的。 MySQL 适用于许多系统平台。今天我们主要分析MySQL协议。

MySQL交换过程

TCP三次握手

我们可以通过网络工具(netcat)登录一个MySQL用户,然后输入命令获取数据库信息。然后使用wireshark工具抓包,在wireshark上分析交换流程。

在这里插入图片描述
MySQL基于的就是TCP的底层协议,需要经历TCP的三次握手。由于TCP要提供可靠的通信机制,在传输数据之前,必须初始化一条客户端到服务器的TCP连接,在连接正式建立后,双方经TCP连接通道进行数据传输。

登陆认证

建立连接之后,MySQL客户端要与服务端进行交互过程。这个时候需要发送认证请求。

在这里插入图片描述
每一个MySQL数据报的报文结构都是如下格式的,报文分为消息头和消息体两部分,其中消息头占用固定四个字节,消息体长度由消息头中的长度字段决定,报文结构如下:

在这里插入图片描述

三次握手后,Server发送第一个认证包,包的格式如下:

在这里插入图片描述Packet Length: 包体的有效长度。
Packet Number:包号。
Protocol: 协议版本,服务端所使用的mysql协议的版本号。
Server Version:服务器版本
Thread ID:连接ID(线程ID),服务端为此客户端所创建的线程的ID。
Salt:8字节用于安全认证的随机数,+1字节的0x00填充。
capalitity :服务器功能标志低2字节。定义如下

#define MYSQL_CAPS_LP 0x0001 /* CLIENT_LONG_PASSWORD */
#define MYSQL_CAPS_FR 0x0002 /* CLIENT_FOUND_ROWS */
#define MYSQL_CAPS_LF 0x0004 /* CLIENT_LONG_FLAG */
#define MYSQL_CAPS_CD 0x0008 /* CLIENT_CONNECT_WITH_DB */
#define MYSQL_CAPS_NS 0x0010 /* CLIENT_NO_SCHEMA */
#define MYSQL_CAPS_CP 0x0020 /* CLIENT_COMPRESS */
#define MYSQL_CAPS_OB 0x0040 /* CLIENT_ODBC */
#define MYSQL_CAPS_LI 0x0080 /* CLIENT_LOCAL_FILES */
#define MYSQL_CAPS_IS 0x0100 /* CLIENT_IGNORE_SPACE */
#define MYSQL_CAPS_CU 0x0200 /* CLIENT_PROTOCOL_41 */
#define MYSQL_CAPS_IA 0x0400 /* CLIENT_INTERACTIVE */
#define MYSQL_CAPS_SL 0x0800 /* CLIENT_SSL */
#define MYSQL_CAPS_II 0x1000 /* CLIENT_IGNORE_SPACE */
#define MYSQL_CAPS_TA 0x2000 /* CLIENT_TRANSACTIONS */
#define MYSQL_CAPS_RS 0x4000 /* CLIENT_RESERVED */
#define MYSQL_CAPS_SC 0x8000 /* CLIENT_SECURE_CONNECTION */

charater set :字符集,服务器默认使用的字符编码。
Server status :服务器状态,服务器状态标志集合。状态值定义如下

/* status bitfield */
#define MYSQL_STAT_IT 0x0001
#define MYSQL_STAT_AC 0x0002
#define MYSQL_STAT_MU 0x0004
#define MYSQL_STAT_MR 0x0008
#define MYSQL_STAT_BI 0x0010
#define MYSQL_STAT_NI 0x0020
#define MYSQL_STAT_CR 0x0040
#define MYSQL_STAT_LR 0x0080
#define MYSQL_STAT_DR 0x0100
#define MYSQL_STAT_BS 0x0200
#define MYSQL_STAT_MC 0x0400
#define MYSQL_STAT_QUERY_WAS_SLOW 0x0800
#define MYSQL_STAT_PS_OUT_PARAMS 0x1000
#define MYSQL_STAT_TRANS_READONLY 0x2000
#define MYSQL_STAT_SESSION_STATE_CHANGED 0x4000

capability flags :服务器功能标志高2字节
plugn data len :加密数据长度.
Unused:保留长度10字节.
plugin data :加密数据剩余部分

客户端收到后返回给用户名,密码等信息。

在这里插入图片描述
Max Packet:客户端发送请求报文时所支持的最大消息长度值。
Charset:标识通讯过程中使用的字符编码,与服务器在认证初始化报文中发送的相同。
Username:客户端登陆的用户名.

认证结果

服务端主要验证,用户名,密码是否正确存在,如果都是正确的,就返回ok报文,错误的话就是ERROR报文,客户端收到Server返回的认证结果如下:

在这里插入图片描述
那么客户端与服务器之间就算彻底链接成功了,接下来就是命令的交互了。

客户端命令请求报文

接下来我们看看客户端命令请求报文,如下:

在这里插入图片描述

Command:用于标识当前请求消息的类型。定义如下:

#define MYSQL_SLEEP               0  /* not from client */
#define MYSQL_QUIT                1
#define MYSQL_INIT_DB             2
#define MYSQL_QUERY               3
#define MYSQL_FIELD_LIST          4
#define MYSQL_CREATE_DB           5
#define MYSQL_DROP_DB             6
#define MYSQL_REFRESH             7
#define MYSQL_SHUTDOWN            8
#define MYSQL_STATISTICS          9
#define MYSQL_PROCESS_INFO        10
#define MYSQL_CONNECT             11 /* not from client */
#define MYSQL_PROCESS_KILL        12
#define MYSQL_DEBUG               13
#define MYSQL_PING                14
#define MYSQL_TIME                15 /* not from client */
#define MYSQL_DELAY_INSERT        16 /* not from client */
#define MYSQL_CHANGE_USER         17
#define MYSQL_BINLOG_DUMP         18 /* replication */
#define MYSQL_TABLE_DUMP          19 /* replication */
#define MYSQL_CONNECT_OUT         20 /* replication */
#define MYSQL_REGISTER_SLAVE      21 /* replication */
#define MYSQL_STMT_PREPARE        22
#define MYSQL_STMT_EXECUTE        23
#define MYSQL_STMT_SEND_LONG_DATA 24
#define MYSQL_STMT_CLOSE          25
#define MYSQL_STMT_RESET          26
#define MYSQL_SET_OPTION          27
#define MYSQL_STMT_FETCH          28
#define MYSQL_DAEMON              29
#define MYSQL_BINLOG_DUMP_GTID    30 /* replication */
#define MYSQL_RESET_CONNECTION    31

弄清楚这些流程以后,我们可以实现了MySQL协议解析。

MySQL协议解析

	if (!is_request) /* response */
	{
		if (packet_number == 0 && mysql_frame_data_p->state == UNDEFINED) 
		{
			printf("Server Greeting \n");
			offset = mysql_dissect_greeting(mysql_data,offset,payload_len,conn_data);
		} 
		else 
		{
			printf("Response \n");
		}
	}
	else /* Request */
	{
		if (stata_value == LOGIN && packet_number == 1 ) 
		{
			printf("Login Request \n");
			
			offset = mysql_dissect_login(mysql_data, offset, payload_len , conn_data);
			if (conn_data->srv_caps & MYSQL_CAPS_CP) 
			{
				if (conn_data->clnt_caps & MYSQL_CAPS_CP) 
				{
					conn_data->frame_start_compressed = pkt_number;
					conn_data->compressed_state = MYSQL_COMPRESS_INIT;
				}
			}
		} 
		else 
		{
			printf("Request \n");
			offset = mysql_dissect_request(mysql_data,offset,packet_length, conn_data);
		}
	}

运行结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

MySQL数据包格式也主要分为两种,一种是Server端向Client端发送的数据包格式,另一种则是Client向Server端发送的数据包。

欢迎关注微信公众号【程序猿编码】,需要MySQL完整源码报文请添加本人微信号(c17865354792)

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值