MySQL协议分析

栏目: 数据库 · 发布时间: 6年前

内容简介:MySQL协议分析,主要参考MySQL Forge上的在做proxy的时候在这里迷糊过,翻了几遍代码才搞明白,细节如下:客户端服务端的net->pkt_nr都从0开始.接受包时比较packet number 和net->pkt_nr是否相等,否则报packet number乱序,连接报错;相等则pkt_nr自增.发送包时把net->pkt_nr作为packet number发送,然后对net->pkt_nr进行自增保持和对端的同步.

MySQL协议分析,主要参考MySQL Forge上的 wiki 和源码.协议的全图见 这里 , 给同事分享的ppt见 这里 ,下载见 这里

packet number

在做proxy的时候在这里迷糊过,翻了几遍代码才搞明白,细节如下:

客户端服务端的net->pkt_nr都从0开始.接受包时比较packet number 和net->pkt_nr是否相等,否则报packet number乱序,连接报错;相等则pkt_nr自增.发送包时把net->pkt_nr作为packet number发送,然后对net->pkt_nr进行自增保持和对端的同步.

接收包

sql/net_serv.c:my_real_read

898     if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)

发送包

sql/net_serv.c:my_net_write

392   int3store(buff,len);
393   buff[3]= (uchar) net->pkt_nr++;

我们来几个具体场景的packet number, net->pkt_nr的变化

连接

0 c ———-> s 0  connect

0 c <—-0——s 1  handshake

2 c —-1—->s 1 auth

2c <—-2——s 0 ok

开始两方都为0,服务端发送handshake packet(pkt=0)之后自增为1,然后等待对端发送过来pkt=1的包

查询

每次查询,服务客户端都会对net->pkt_nr进行清零

include/mysql_com.h
388 #define net_new_transaction(net) ((net)->pkt_nr=0)
sql/sql_parse.cc:do_command
805   net_new_transaction(net);

sql/client.c:cli_advanced_command

800   net_clear(&mysql->net, (command != COM_QUIT));

开始两方net->pkt_nr皆为0, 命令发送后客户端端为1,服务端开始发送分包,分包的pkt_nr的依次递增,客户端的net->pkt_nr也随之增加.

1 c ——0—-> s 0  query

1 c <—-1——s 2  resultset

2 c <—-2——s 3  resultset

解包的细节

my_net_read负责解包,首先读取4个字节,判断packet number是否等于net->pkt_nr然后再次读取packet_number长度的包体。

伪代码如下:

remain=4
for(i = 0; i < 2; i++) {
    //数据是否读完
    while (remain>0)  {
        length = read(fd, net->buff, remain)
        remain = remain - length
    }
    //第一次
    if (i=0) {
        remain = uint3korr(net->buff+net->where_b);
    }
}

网络层优化

从ppt里可以看到,一个resultset packet由多个包组成,如果每次读写包都导致系统调用那肯定是不合理,常规优化方法:写大包加预读

net->buff

每个包发送到网络或者从网络读包都会先把数据包保存在net->buff里,待到net->buff满了或者一次命令结束才会通过socket发出给对端.net->buff有个初始大小(net->max_packet),会随读取数据的增多而扩展.

vio->read_buffer

每次从网络读包,并不是按包的大小读取,而是会尽量读取2048个字节,这样一个resultset包的读取不会再引起多次的系统调用了.header packet读取完毕后, 接下来的field,eof, row apcket读取仅仅需要从vio-read_buffer拷贝指定字节的数据即可.

MySQL api说明

api和 MySQL 客户端都会使用sql/client.c这个文件,解包的过程都是使用sql/client.c:cli_read_query_result.

mysql_store_result来解析row packet,并把数据存储到res->data里,此时所有数据都存内存里了.

mysql_fetch_row仅仅是使用内部的游标,遍历result->data里的数据

3052     if (!res->data_cursor)
3053     {
3054       DBUG_PRINT("info",("end of data"));
3055       DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
3056     }
3057     tmp = res->data_cursor->data;
3058     res->data_cursor = res->data_cursor->next;
3059     DBUG_RETURN(res->current_row=tmp);

mysql_free_result是把result->data指定的行数据释放掉.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JavaScript Patterns

JavaScript Patterns

Stoyan Stefanov / O'Reilly Media, Inc. / 2010-09-21 / USD 29.99

What's the best approach for developing an application with JavaScript? This book helps you answer that question with numerous JavaScript coding patterns and best practices. If you're an experienced d......一起来看看 《JavaScript Patterns》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具