内容简介: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见 这里 ,下载见 这里
View more presentations from ruoyi ruan
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指定的行数据释放掉.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用动态分析技术分析 Java
- 使用动态分析技术分析 Java
- 案例分析:如何进行需求分析?
- 深度分析ConcurrentHashMap原理分析
- 如何分析“数据分析师”的岗位?
- EOS源码分析(3)案例分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
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 HEX 互转工具
XML、JSON 在线转换
在线XML、JSON转换工具