MySQL協議分析

發表于:2013-10-14來源:IT博客大學習作者:hoterran點擊數: 標簽:MySQL
每個包發送到網絡或者從網絡讀包都會先把數據包保存在net->buff里,待到net->buff滿了或者一次命令結束才會通過socket發出給對端.net->buff有個初始大小(net->max_packet),會隨讀取數據的增多而擴展.

  MySQL協議分析,主要參考MySQL Forge上的wiki和源碼.協議的全圖見這里, 給同事分享的ppt見這里,下載見這里

  MySQL協議分析

  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指定的行數據釋放掉.

原文轉自:http://blogread.cn/it/article/5604

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97