zoukankan      html  css  js  c++  java
  • [知识整理] Mysql Driver & 协议解析

    曾经在负责Mysql时,那会觉得IO就应该是异步的,但是C# 版本Mysql Driver竟然只支持同步调用方式,简直不可接受哇。

    然后就研究Mysql Driver,并改了一版异步的实现,并且做了一次小组分享: PPT抓包分析 (2011/11/3)。

    接下来为应对故障排查,也做了一版将Mysql 的Pcap抓包解析成为明文文本的工具,就是下文了。想想那会儿真是比较闲了,还能折腾点儿事,最近两年陷入业务不可自拔,荒废了。。。

    Mysql的客户服服务器协议还是比较简单的,官方有详细的协议说明:http://dev.mysql.com/doc/internals/en/client-server-protocol.html

    曾经想写协议解析工具,是为了mysql相关的问题排查和mysql请求统计分析,后来觉得重要性不高,没时间做、只完成request部分解析。

    代码写了一部分,不过也能正常工作了,记录一下:

       1:  class MysqlQueryParser : MysqlParser
       2:      {
       3:          private enum ParsingState { PacketHead, Body }
       4:          private StreamBuffer _buffer;
       5:          private ParsingState _state;
       6:          private MysqlQueryPacket _packet;
       7:          public MysqlQueryParser()
       8:          {
       9:              SipcStack.Initialize();
      10:              _buffer = new StreamBuffer();
      11:              _state = ParsingState.PacketHead;
      12:              _packet = new MysqlQueryPacket();
      13:          }
      14:   
      15:          public override void Parse(byte[] data)
      16:          {
      17:              _buffer.Write(data);
      18:              TryParse();
      19:          }
      20:   
      21:          private void TryParse()
      22:          {
      23:              if (_state == ParsingState.PacketHead)
      24:              {
      25:                  if (_buffer.Size >= 4)
      26:                  {
      27:                      byte[] head = new byte[4];
      28:                      _buffer.Read(head, 0, 4);
      29:                      ReadPacketHeader(head, out _packet.PacketLength, out _packet.PacketNum);
      30:                      _state = ParsingState.Body;
      31:                  }
      32:                  else
      33:                      return;
      34:              }
      35:   
      36:              if (_state == ParsingState.Body)
      37:              {
      38:                  if (_buffer.Size >= _packet.PacketLength)
      39:                  {
      40:                      byte[] body = new byte[_packet.PacketLength];
      41:                      _buffer.Read(body, 0, _packet.PacketLength);
      42:                      _packet.Body = body;
      43:                      _packet.Command = (DBCmd)body[0];
      44:                      HandleParseOk();
      45:                  }
      46:              }
      47:          }
      48:   
      49:          private void HandleParseError(string msg)
      50:          {
      51:              _buffer.Close();
      52:              _state = ParsingState.PacketHead;
      53:              _packet = new MysqlQueryPacket();
      54:   
      55:              if (OnParsedError != null)
      56:                  OnParsedError();
      57:          }
      58:   
      59:          private void HandleParseOk()
      60:          {
      61:              if (OnParsedPacket != null)
      62:              {
      63:                  _packet.Time = LastTime;
      64:                  _packet.SrcEP = LastSrcEP;
      65:                  _packet.DstEP = LastDstEP;
      66:                  OnParsedPacket(_packet);
      67:              }
      68:              _state = ParsingState.PacketHead;
      69:              _packet = new MysqlQueryPacket();
      70:          }
      71:      }
       1:    enum ResultSetType
       2:      {
       3:          OK,
       4:          Error,
       5:          ResultSet,
       6:      }
       7:   
       8:      class MysqlResultSetPacket : MysqlPacket
       9:      {
      10:          public MysqlResultSetPacket()
      11:          {
      12:              PacketType = PacketType.ResultSet;
      13:          }
      14:   
      15:          public ResultSetType ResultSetType { get; set; }
      16:      }
      17:   
      18:      class MysqlOKResultSet : MysqlResultSetPacket
      19:      {
      20:          public MysqlOKResultSet()
      21:          {
      22:              ResultSetType = ResultSetType.OK;
      23:          }
      24:          public int PacketLength;
      25:          public int PacketNum;
      26:          public int AffectRow;
      27:          public int ServerState;
      28:          public string Message;
      29:      }
      30:   
      31:      class MysqlOKResultSet : MysqlResultSetPacket
      32:      {
      33:          public MysqlOKResultSet()
      34:          {
      35:              ResultSetType = ResultSetType.Error;
      36:          }
      37:          public int PacketLength;
      38:          public int PacketNum;
      39:          public int ErrorNum;
      40:          public int SqlState;
      41:          public string Message;
      42:      }
      43:   
      44:      class MysqlDataResultSet : MysqlResultSetPacket
      45:      {
      46:          public ResultSetHeadPacket HeadPacket;
      47:          public List<ResultSetFieldPacket> FieldPacket;
      48:          public List<ResultSetRowPacket> RowPacket;
      49:   
      50:          public MysqlDataResultSet()
      51:          {
      52:              ResultSetType = ResultSetType.ResultSet;
      53:          }
      54:      }
      55:   
      56:      public class ResultSetHeadPacket
      57:      {
      58:          public int PacketLength;
      59:          public int PacketNum;
      60:          public int FieldNum;
      61:      }
      62:   
      63:      public class ResultSetFieldPacket
      64:      {
      65:          public int PacketLength;
      66:          public int PacketNum;
      67:      }
      68:   
      69:      public class ResultSetRowPacket
      70:      {
      71:          public int PacketLength;
      72:          public int PacketNum;
      73:      }
       1:  abstract class MysqlParser
       2:      {
       3:          public Action<MysqlPacket> OnParsedPacket;
       4:          public  Action OnParsedError;
       5:   
       6:          public DateTime LastTime { get; set; }
       7:          public IPEndPoint LastSrcEP { get; set; }
       8:          public IPEndPoint LastDstEP { get; set; }
       9:   
      10:          public abstract void Parse(byte[] data);
      11:   
      12:          //The Packet Header
      13:          //Bytes                 Name
      14:          // -----                 ----
      15:          // 3                     Packet Length
      16:          // 1                     Packet Number
      17:   
      18:          // Packet Length: The length, in bytes, of the packet
      19:          //                that follows the Packet Header. There
      20:          //                may be some special values in the most
      21:          //                significant byte. The maximum packet 
      22:          //                length is (2**24 -1),about 16MB.
      23:   
      24:          // Packet Number: A serial number which can be used to
      25:          //                ensure that all packets are present
      26:          //                and in order. The first packet of a
      27:          //                client query will have Packet Number = 0
      28:          //                Thus, when a new SQL statement starts, 
      29:          //                the packet number is re-initialised.
      30:   
      31:          protected void ReadPacketHeader(byte[] header,out int packetLength,out int packetNum)
      32:          {
      33:              if (header == null || header.Length != 4)
      34:                  throw new ArgumentException();
      35:   
      36:              packetLength = (int)header[0] + (((int)header[1]) << 8) + (((int)header[3]) << 16);
      37:              packetNum = header[3];
      38:          }
      39:      }
       1:  class MysqlQueryPacket : MysqlPacket
       2:      {
       3:          public MysqlQueryPacket()
       4:          {
       5:              this.PacketType = PacketType.Query;
       6:          }
       7:          public int PacketLength;
       8:          public int PacketNum;
       9:          public byte[] Body;
      10:          public DBCmd Command;
      11:   
      12:          private string _commandArgs;
      13:          public string CommandArgs
      14:          {
      15:              get
      16:              {
      17:                  if (Command == DBCmd.QUERY && Body != null && Body.Length > 0)
      18:                  {
      19:                      if (_commandArgs == null)
      20:                          _commandArgs = Encoding.UTF8.GetString(Body,1,Body.Length-1);
      21:                  }
      22:   
      23:                  return _commandArgs;
      24:              }
      25:          }
      26:   
      27:          public MysqlCommandArgs ResolveCommand()
      28:          {
      29:              MysqlCommandArgs args = new MysqlCommandArgs();
      30:              args.CmdType = CommandType.Text;
      31:              if (CommandArgs != null)
      32:              {
      33:                  if (CommandArgs.Substring(0, 4) == "CALL")
      34:                  {
      35:                      args.CmdType = CommandType.StoredProcedure;
      36:   
      37:                      int start = CommandArgs.IndexOf("(");
      38:                      if (start > 3)
      39:                          args.ResolveQuery = CommandArgs.Substring(3, start - 3);
      40:                  }
      41:                  else
      42:                  {
      43:                      //todo replace ='xx' to ={}
      44:                  }
      45:              }
      46:   
      47:              return args;
      48:          }
      49:      }
      50:   
      51:      class MysqlCommandArgs
      52:      {
      53:          public CommandType CmdType { get; set; }
      54:          public string ResolveQuery { get; set; }
      55:      }
       1:   enum PacketType
       2:      {
       3:          Query,
       4:          ResultSet,
       5:      }
       6:      class MysqlPacket
       7:      {
       8:          public DateTime Time { get; set; }
       9:          public IPEndPoint SrcEP { get; set; }
      10:          public IPEndPoint DstEP { get; set; }
      11:   
      12:          public PacketType PacketType { get; set; }
      13:      }
       1:  enum DBCmd : byte
       2:      {
       3:          SLEEP = 0,
       4:          QUIT = 1,
       5:          INIT_DB = 2,
       6:          QUERY = 3,
       7:          FIELD_LIST = 4,
       8:          CREATE_DB = 5,
       9:          DROP_DB = 6,
      10:          RELOAD = 7,
      11:          SHUTDOWN = 8,
      12:          STATISTICS = 9,
      13:          PROCESS_INFO = 10,
      14:          CONNECT = 11,
      15:          PROCESS_KILL = 12,
      16:          DEBUG = 13,
      17:          PING = 14,
      18:          TIME = 15,
      19:          DELAYED_INSERT = 16,
      20:          CHANGE_USER = 17,
      21:          BINLOG_DUMP = 18,
      22:          TABLE_DUMP = 19,
      23:          CONNECT_OUT = 20,
      24:          REGISTER_SLAVE = 21,
      25:          PREPARE = 22,
      26:          EXECUTE = 23,
      27:          LONG_DATA = 24,
      28:          CLOSE_STMT = 25,
      29:          RESET_STMT = 26,
      30:          SET_OPTION = 27,
      31:          FETCH = 28
      32:      }
  • 相关阅读:
    Algorithm Gossip (48) 上三角、下三角、对称矩阵
    .Algorithm Gossip (47) 多维矩阵转一维矩阵
    Algorithm Gossip (46) 稀疏矩阵存储
    Algorithm Gossip (45) 费氏搜寻法
    Algorithm Gossip (44) 插补搜寻法
    Algorithm Gossip (43) 二分搜寻法
    Algorithm Gossip (42) 循序搜寻法(使用卫兵)
    Algorithm Gossip (41) 基数排序法
    Algorithm Gossip (40) 合并排序法
    AlgorithmGossip (39) 快速排序法 ( 三 )
  • 原文地址:https://www.cnblogs.com/lulu/p/3130837.html
Copyright © 2011-2022 走看看