MySQL協議分析

jopen 9年前發布 | 53K 次閱讀 MySQL 數據庫服務器

參考資料:

http://dev.mysql.com/doc/internals/en/client-server-protocol.html

http://www.haodaima.net/art/2574673

http://hutaow.com/blog/2013/11/06/mysql-protocol-analysis/#11

http://blog.csdn.net/gapaul/article/details/12046843



mysql起始握手,先由server發起,client分析并回應自已同意的特性,然后雙方依照這些特性處理數據包。

通信時是否采用壓縮會改變數據包的字節變化。

客戶端的特性在首個回應(既握手包)服務器中體現,如:是否開啟壓縮、字符集、用戶登錄信息等。


1.未采用壓縮時,客戶端向服務器發送的包格式:

格式:3*byte,1*byte,1*byte,n*byte

表示:消息長度,包序號,請求類型,請求內容


2.采用壓縮后,客戶端向服務器發送的包格式:

格式:3*byte,1*byte,3*byte,3*byte,n*byte

表示:消息長度,包序號,壓縮包大小,壓縮包內容

當壓縮包大小為0x00時,表示當前包未采用壓縮,則n*byte內容為1*byte,n*byte,既請求類型,請求內容

當壓縮包大小大于0x00時,表示當前包已采用zlib壓縮,則n*byte內容,先解壓縮,解壓后內容為1*byte,n*byte,既請求類型,請求內容。


package mysql;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * 支持mysql 4.1+,不支持ssl
 * @author shanl
 *
 */
public class MysqlAnalyse {
    /**傳輸包默認最大長度16M*/
    public static final int PACKET_MAXIMUM_LENGTH = 1024*1024*16;

    Map<String,Object> properties = new HashMap<String,Object>();
//  StringBuilder sql = new StringBuilder();
    long requestType = -1;
    boolean endPacket = true;

//  int packetLen = PACKET_MAXIMUM_LENGTH;   
    byte[] _packet = null;
    int _off = 0;
    int _len = 0;

    /**
     * 默認開啟壓縮、utf-8編碼
     */
    public MysqlAnalyse(){
        this.setProperty("compress", true);
        this.setProperty("encoding", "utf-8");
    }

    /**
     * <b>通過客戶端向服務端回應的握手包,獲得一個MysqlAnlayse實例。</b> <br/>
     * 建立連接時,server先向client發送握手包,此包包括server支持的特性和編碼等信息,<br/>
     * client回應包中需要說明本地支持什么特性,比如是否支持(zlib)壓縮。
     * @param buff
     * @param off
     * @param len
     * @return
     * @see <a >
     * http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse<a/>   
     */
    public static MysqlAnalyse handshake(byte[] buff,int off,int len){
        MysqlAnalyse anly = new MysqlAnalyse();
        //2 byte,capability_flags
        long capability_flags = Util.bigBys2Uint32(new byte[]{
                buff[off],buff[off+1]
        }, 0, 2);

        //4byte,前2byte表示mysql特性(如下:是否開啟壓縮),后2byte客戶端擴展特性
        boolean compress = CapabilityFlag.CLIENT_COMPRESS==(CapabilityFlag.CLIENT_COMPRESS & capability_flags);
        anly.setProperty("compress", compress);        

        //4byte,最大發送包字節數
        long max_packet_size = Util.bigBys2Uint32(new byte[]{
                buff[off+4],buff[off+5],
                buff[off+6],buff[off+7]
        }, 0, 4);
        anly.setProperty("max.packet.size", max_packet_size);

        //1byte,字符編碼
        short character_set_id = buff[8];
        String character_set = "latin1"; //需要分析
        anly.setProperty("encoding", character_set);

        return anly;
    }

    /**
     * <b> 解析數據包  </b> <br/>
     未壓縮:指客戶端已開啟壓縮功能,但數據包本身不值得壓縮,所以未進行壓縮。<br/>
     未開啟壓縮:指客戶端未開啟壓縮功能,比如:./mysql 沒有加-C, --compress參數。<br/>
     客戶端開啟壓縮功能后,向服務器發送數據包時,將會在包頭(3+1字節)后,額外多3個字節,<br/>
     表示壓縮包大小,如果此值為0x000000(小端字節順),則表示數據未壓縮。 
     * @param buff
     * @param off
     * @param len
     * @return 如果是最后一個包返回true
     */
    public boolean parse(byte[] packet,int off,int len){
//      sql = endPacket? new StringBuilder():sql;               
//      _buff = (null==_buff? new byte[packetLen]: _buff);
//      _buff = packet;
//      _off = off;
//      _len = len;

        if((Boolean)properties.get("compress")){
            endPacket=compress(packet,off,len);
        }else{
            endPacket=noncompress(packet,off,len);
        }       

        return endPacket;
    }

    /**
     * (客戶端)支持壓縮
     * @param packet
     * @param off
     * @param len
     */
    boolean compress(byte[] packet,int off,int len){
        long tranPackLen = Util.littleBys2Uint32(packet,off+0,3);       //3 byte,傳輸包長度,此長度已經-7
        short tranPackNo = packet[off+3];                                //1 byte,傳輸包序號
        long compressPackLen = Util.littleBys2Uint32(packet,off+4,3);    //3 byte,壓縮后包長度

        //未壓縮
        if(0x000000==compressPackLen){          
            long srcLen = Util.littleBys2Uint32(packet,off+3+1+3,4)-1;   //4byte,(包含類型信息的)源數據長度
            this.requestType = packet[off+3+1+3+4];                       //1byte,類型信息
            _packet = packet;
            _off = off+3+1+3;
            _len = (int)srcLen;
//          sql.append(toSql(packet, off+3+1+3, (int)srcLen));
        }else{ //已壓縮
            byte[] src = Util.decompress(packet,off+3+1+3,
                    (int)tranPackLen,(int)compressPackLen);             //n byte,src為zlib解壓后的源數據
            long srcLen = Util.littleBys2Uint32(src,0,4)-1;              //4byte,(包含類型信息的)源數據長度
            this.requestType = src[4];                                    //1byte,類型信息
            _packet = src;
            _off = 0;
            _len = (int) srcLen;
//          sql.append(toSql(src,0,(int)srcLen));
        }

        return 0x00==tranPackNo;
    }

    /**
     * (客戶端)不支持壓縮
     * @param packet
     * @param off
     * @param len
     */
    boolean noncompress(byte[] packet,int off,int len){
        long tranPackLen = Util.littleBys2Uint32(packet,off+0,3);   //3 byte
        short tranPackNo = packet[off+3];                            //1 byte
        this.requestType = packet[off+4];                         //1 byte

//      sql.append(toSql(packet,off,(int)tranPackLen));
        _packet = packet;
        _off = off;
        _len = (int)tranPackLen;

        return 0x00==tranPackNo;
    }

    /**
     * 當前包中的sql語句<br/>
     * 注:這不一定是一個完整的sql語句<br/>
     * @param packet
     * @param off
     * @param len
     * @return 當requestType!=ClientRequestType.COM_QUERY時,返回""
     */
    String toSql(byte[] packet,int off,int len){        
        try {
            return new String(packet,off+5,len, (String)getProperty("encoding"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);            
        }
    }

    /**
     * 返回sql語句 <br/>
     * 只有當requestType==ClientRequestType.COM_QUERY時可用
     * @return 類型不符合時,返回""
     */
    public String getSql(){
        if(ClientRequestType.COM_QUERY!=this.requestType){
            return "";
        }       
//      return sql.toString();
        return toSql(_packet,_off,_len);
    }

    /**
     * 返回當前sql請求類型,參見ClientRequestType
     * @return 未知請求返回-1
     */
    public long getRequestType(){
        return requestType;
    }

    /**
     * 設置特性
     * @param name
     * @param value
     */
    public void setProperty(String name,Object value){
        this.properties.put(name, value);
    }

    /**
     * 設置特性
     * @param properties
     */
    public void putProperty(Map<String,Object> properties){
        this.properties.putAll(properties);;
    }

    /**
     * 取特性
     * @param name
     * @return
     */
    public Object getProperty(String name){
        return this.properties.get(name);
    }

    /**
     * 返回所有特性
     * @return
     */
    public Map<String,Object> getProperties(){
        return this.properties;
    }

//  /**
//   * 設置傳輸包大小<br/>
//   * 默認值   PACKET_MAXIMUM_LENGTH
//   * @param len
//   * @see #PACKET_MAXIMUM_LENGTH
//   */
//  public void setTranPacketLength(int len){
//      this.packetLen = len;
//  }
}
package mysql;

/**
 * 特性
 * @author shanl
 * @see <a >http://dev.mysql.com/doc/internals/en/capability-flags.html#flag-CLIENT_PROTOCOL_41</a> 
 */
public interface CapabilityFlag {
    long CLIENT_LONG_PASSWORD         =  0x00000001; 
    long CLIENT_FOUND_ROWS         =  0x00000002;
    long CLIENT_LONG_FLAG          =  0x00000004; 
    long CLIENT_CONNECT_WITH_DB   =  0x00000008;

    long CLIENT_NO_SCHEMA          =  0x00000010;
    long CLIENT_COMPRESS          =   0x00000020;
    long CLIENT_ODBC              =  0x00000040;
    long CLIENT_LOCAL_FILES       =  0x00000080;

    long CLIENT_IGNORE_SPACE       =  0x00000100;
    long CLIENT_PROTOCOL_41            =  0x00000200;
    long CLIENT_INTERACTIVE       =  0x00000400;
    long CLIENT_SSL                    =  0x00000800;

    long CLIENT_IGNORE_SIGPIPE     =  0x00001000;
    long CLIENT_TRANSACTIONS       =  0x00002000;
    long CLIENT_RESERVED          =  0x00004000;
    long CLIENT_SECURE_CONNECTION  =   0x00008000;

    long CLIENT_MULTI_STATEMENTS   =  0x00010000;
    long CLIENT_MULTI_RESULTS      =  0x00020000;
    long CLIENT_PS_MULTI_RESULTS   =  0x00040000;
    long CLIENT_PLUGIN_AUTH            =  0x00080000;

    long CLIENT_CONNECT_ATTRS                      =  0x00100000;
    long CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA     =   0x00200000;
    long CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS       =  0x00400000;
    long CLIENT_SESSION_TRACK                      =  0x00800000;

    long CLIENT_DEPRECATE_EOF      =   0x01000000; 
}
package mysql;

/**
 * 客戶端請求類型
 * @author shanl
 * @see <a >http://dev.mysql.com/doc/internals/en/text-protocol.html</a> 
 */
public interface ClientRequestType {
    /**(內部線程狀態)*/
    int COM_SLEEP                  =  0x00;
    /**關閉連接*/
    int COM_QUIT                  =  0x01;
    /**切換數據庫*/
    int COM_INIT_DB               =  0x02;
    /**SQL查詢請求*/
    int COM_QUERY                     =  0x03;

    /**獲取數據表字段信息*/
    int COM_FIELD_LIST                =  0x04;
    /**創建數據庫*/
    int COM_CREATE_DB                 =  0x05;
    /**刪除數據庫*/
    int COM_DROP_DB               =  0x06;
    /**清除緩存*/
    int COM_REFRESH               =  0x07;

    /**停止服務器*/
    int COM_SHUTDOWN              =  0x08;
    /**獲取服務器統計信息*/
    int COM_STATISTICS                =  0x09;
    /**獲取當前連接的列表*/
    int COM_PROCESS_INFO          =  0x0A;
    /**(內部線程狀態)*/
    int COM_CONNECT               =  0x0B;

    /**中斷某個連接*/
    int COM_PROCESS_KILL          =  0x0C;
    /**保存服務器調試信息*/
    int COM_DEBUG                     =  0x0D;
    /**測試連通性*/
    int COM_PING                  =  0x0E;
    /**(內部線程狀態)*/
    int COM_TIME                   =  0x0F;

    /**(內部線程狀態)*/
    int COM_DELAYED_INSERT            =  0x10;
    /**重新登陸(不斷連接*/
    int COM_CHANGE_USER           =   0x11;
    /**獲取二進制日志信息*/
    int COM_BINLOG_DUMP                =  0x12;
    /**獲取數據表結構信息*/
    int COM_TABLE_DUMP             =  0x13;

    /**(內部線程狀態)*/
    int COM_CONNECT_OUT           =  0x14;
    /**從服務器向主服務器進行注冊*/
    int COM_REGISTER_SLAVE         =  0x15;
    /**預處理SQL語句*/
    int COM_STMT_PREPARE          =  0x16;
    /**執行預處理語句*/
    int COM_STMT_EXECUTE          =  0x17;

    /**發送BLOB類型的數據*/
    int COM_STMT_SEND_LONG_DATA        =   0x18;
    /**銷毀預處理語句*/
    int COM_STMT_CLOSE             =  0x19;
    /**清除預處理語句參數緩存*/
    int COM_STMT_RESET                =  0x1A;
    /**設置語句選項*/
    int COM_SET_OPTION                =  0x1B;

    /**獲取預處理語句的執行結果*/
    int COM_STMT_FETCH             =  0x1C;
}


package mysql;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.zip.Inflater;

/**
 * 為mysql分析專用工具
 * @author shanl
 *
 */
public class Util {
    /**
     * Big-Endian字節數組轉uint32
     * @param bys
     * @param off
     * @param len
     * @return
     */
    public static long bigBys2Uint32(byte[] bys,int off,int len){
        long uint32 = 0;
        for(int i=0,end=len-1,c=end; i<=end; i++,c--){
            uint32 |= (0xff&bys[off+i])<<(8*c);
        }
        return uint32;     
    }

    /**
     * Little-Endian字節數組轉uint32
     * @param bys
     * @param off
     * @param len
     * @return
     */
    public static long littleBys2Uint32(byte[] bys,int off,int len){
        long uint32 = 0;
        for(int i=len-1; i>=0; i--){          
            uint32 |= (0xff&bys[off+i])<<(8*i);
        }
        return uint32;
    }

    /**
     * 適用于mysql與客戶端交互時zlib解壓
     * @param data
     * @param off
     * @param len
     * @param out
     * @throws Exception
     */
    public static void decompress(byte[] data, int off, int len,OutputStream out){
        Inflater decompresser = new Inflater();  
        decompresser.reset();
        decompresser.setInput(data, off, len);
        byte[] buf = new byte[1024];

        try{
            while(!decompresser.finished()){
                int i = decompresser.inflate(buf);
                out.write(buf, 0, i);
                out.flush();
            }
        }catch(Exception ex){
            throw new RuntimeException(ex);
        }
    }

    /**
     * 適用于mysql與客戶端交互時zlib解壓
     * @param data 數據
     * @param off 偏移量
     * @param len 長度
     * @return
     */
    public static byte[] decompress(byte[] data, int off, int len) {  
        byte[] output = null; 
        Inflater decompresser = new Inflater();  
        decompresser.reset();         
//      decompresser.setInput(data);
        decompresser.setInput(data, off, len);        
          
        ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);  
        try {  
            byte[] buf = new byte[1024];  
            while (!decompresser.finished()) {  
                int i = decompresser.inflate(buf);  
                o.write(buf, 0, i);  
            }  
            output = o.toByteArray();  
        } catch (Exception e) {
            throw new RuntimeException(e);  
        } finally {  
            try {  
                o.close();  
            } catch (Exception e) {
            }  
        }  
  
        decompresser.end();  
        return output;  
    }

    /**
     * 適用于mysql與客戶端交互時zlib解壓
     * @param data 數據
     * @param off 偏移量
     * @param len 長度
     * @param srcLen 源數據長度
     * @return
     */
    public static byte[] decompress(byte[] data, int off, int len, int srcLen) {  
        byte[] output = null; 
        Inflater decompresser = new Inflater();  
        decompresser.reset();         
//      decompresser.setInput(data);
        decompresser.setInput(data, off, len);        
          
        ByteArrayOutputStream o = new ByteArrayOutputStream(srcLen);  
        try {  
            o.reset();
            byte[] buf = new byte[1024];  
            while (!decompresser.finished()) {  
                int i = decompresser.inflate(buf);  
                o.write(buf, 0, i);  
            }  
            output = o.toByteArray();  
        } catch (Exception e) {
            throw new RuntimeException(e);  
        } finally {  
            try {  
                o.close();  
            } catch (Exception e) {
            }  
        }  
  
        decompresser.end();  
        return output;  
    }
}
package mysql;

/**
 * 支持的字符編碼
 * @author shanl
 * @see <a >
 * http://dev.mysql.com/doc/internals/en/character-set.html#packet-Protocol::CharacterSet</a>
 */
public class CharacterSet {
    /***
      int big5_chinese_ci              =1;  
      int latin2_czech_cs              =2;  
      int dec8_swedish_ci              =3;  
      int cp850_general_ci             =4;  
      int latin1_german1_ci            =5;  
      int hp8_english_ci               =6;  
      int koi8r_general_ci             =7;  
      int latin1_swedish_ci            =8;  
      int latin2_general_ci            =9;  
      int swe7_swedish_ci             =10;  
      int ascii_general_ci            =11;  
      int ujis_japanese_ci            =12;  
      int sjis_japanese_ci            =13;  
      int cp1251_bulgarian_ci         =14;  
      int latin1_danish_ci            =15;  
      int hebrew_general_ci           =16;  
      int tis620_thai_ci              =18;  
      int euckr_korean_ci             =19;  
      int latin7_estonian_cs          =20;  
      int latin2_hungarian_ci         =21;  
      int koi8u_general_ci            =22;  
      int cp1251_ukrainian_ci         =23;  
      int gb2312_chinese_ci           =24;  
      int greek_general_ci            =25;  
      int cp1250_general_ci           =26;  
      int latin2_croatian_ci          =27;  
      int gbk_chinese_ci              =28;  
      int cp1257_lithuanian_ci        =29;  
      int latin5_turkish_ci           =30;  
      int latin1_german2_ci           =31;  
      int armscii8_general_ci         =32;  
      int utf8_general_ci             =33;  
      int cp1250_czech_cs             =34;  
      int ucs2_general_ci             =35;  
      int cp866_general_ci            =36;  
      int keybcs2_general_ci          =37;  
      int macce_general_ci            =38;  
      int macroman_general_ci         =39;  
      int cp852_general_ci            =40;  
      int latin7_general_ci           =41;  
      int latin7_general_cs           =42;  
      int macce_bin                   =43;  
      int cp1250_croatian_ci          =44;  
      int utf8mb4_general_ci          =45;  
      int utf8mb4_bin                 =46;  
      int latin1_bin                  =47;  
      int latin1_general_ci           =48;  
      int latin1_general_cs           =49;  
      int cp1251_bin                  =50;  
      int cp1251_general_ci           =51;  
      int cp1251_general_cs           =52;  
      int macroman_bin                53  
      int utf16_general_ci            54  
      int utf16_bin                   55  
      int cp1256_general_ci           57  
      int cp1257_bin                  58  
      int cp1257_general_ci           59  
      int utf32_general_ci            60  
      int utf32_bin                   61  
      int binary                      63  
      int armscii8_bin                64  
      int ascii_bin                   65  
      int cp1250_bin                  66  
      int cp1256_bin                  67  
      int cp866_bin                   68  
      int dec8_bin                    69  
      int greek_bin                   70  
      int hebrew_bin                  71  
      int  hp8_bin                     72  
      int keybcs2_bin                 73  
      int koi8r_bin                   74  
      int koi8u_bin                   75  
      int latin2_bin                  77  
      int latin5_bin                  78  
      int latin7_bin                  79  
      int cp850_bin                   80  
      int cp852_bin                   81  
      int swe7_bin                    82  
      int utf8_bin                    83  
      int big5_bin                    84  
      int euckr_bin                   85  
      int gb2312_bin                  86  
      int gbk_bin                     87  
      int sjis_bin                    88  
      int tis620_bin                  89  
      int ucs2_bin                    90  
      int ujis_bin                    91  
      int geostd8_general_ci          92  
      int geostd8_bin                 93  
      latin1_spanish_ci           94  
      cp932_japanese_ci           95  
      cp932_bin                   96  
      eucjpms_japanese_ci         97  
      eucjpms_bin                 98  
      cp1250_polish_ci            99  
      utf16_unicode_ci           101  
      utf16_icelandic_ci         102  
      utf16_latvian_ci           103  
      utf16_romanian_ci          104  
      utf16_slovenian_ci         105  
      utf16_polish_ci            106  
      utf16_estonian_ci          107  
      utf16_spanish_ci           108  
      utf16_swedish_ci           109  
      utf16_turkish_ci           110  
      utf16_czech_ci             111  
      utf16_danish_ci            112  
      utf16_lithuanian_ci        113  
      utf16_slovak_ci            114  
      utf16_spanish2_ci          115  
      utf16_roman_ci             116  
      utf16_persian_ci           117  
      utf16_esperanto_ci         118  
      utf16_hungarian_ci         119  
      utf16_sinhala_ci           120  
      ucs2_unicode_ci            128  
      ucs2_icelandic_ci          129  
      ucs2_latvian_ci            130  
      ucs2_romanian_ci           131  
      ucs2_slovenian_ci          132  
      ucs2_polish_ci             133  
      ucs2_estonian_ci           134  
      ucs2_spanish_ci            135  
      ucs2_swedish_ci            136  
      ucs2_turkish_ci            137  
      ucs2_czech_ci              138  
      ucs2_danish_ci             139  
      ucs2_lithuanian_ci         140  
      ucs2_slovak_ci             141  
      ucs2_spanish2_ci           142  
      ucs2_roman_ci              143  
      ucs2_persian_ci            144  
      ucs2_esperanto_ci          145  
      ucs2_hungarian_ci          146  
      ucs2_sinhala_ci            147  
      ucs2_general_mysql500_ci   159  
      utf32_unicode_ci           160  
      utf32_icelandic_ci         161  
      utf32_latvian_ci           162  
      utf32_romanian_ci          163  
      utf32_slovenian_ci         164  
      utf32_polish_ci            165  
      utf32_estonian_ci          166  
      utf32_spanish_ci           167  
      utf32_swedish_ci           168  
      utf32_turkish_ci           169  
      utf32_czech_ci             170  
      utf32_danish_ci            171  
      utf32_lithuanian_ci        172  
      utf32_slovak_ci            173  
      utf32_spanish2_ci          174  
      utf32_roman_ci             175  
      utf32_persian_ci           176  
      utf32_esperanto_ci         177  
      utf32_hungarian_ci         178  
      utf32_sinhala_ci           179  
      utf8_unicode_ci            192  
      utf8_icelandic_ci          193  
      utf8_latvian_ci            194  
      utf8_romanian_ci           195  
      utf8_slovenian_ci          196  
      utf8_polish_ci             197  
      utf8_estonian_ci           198  
      utf8_spanish_ci            199  
      utf8_swedish_ci            200  
      utf8_turkish_ci            201  
      utf8_czech_ci              202  
      utf8_danish_ci             203  
      utf8_lithuanian_ci         204  
      utf8_slovak_ci             205  
      utf8_spanish2_ci           206  
      utf8_roman_ci              207  
      utf8_persian_ci            208  
      utf8_esperanto_ci          209  
      utf8_hungarian_ci          210  
      utf8_sinhala_ci            211  
      utf8_general_mysql500_ci   223  
      utf8mb4_unicode_ci         224  
      utf8mb4_icelandic_ci       225  
      utf8mb4_latvian_ci         226  
      utf8mb4_romanian_ci        227  
      utf8mb4_slovenian_ci       228  
      utf8mb4_polish_ci          229  
      utf8mb4_estonian_ci        230  
      utf8mb4_spanish_ci         231  
      utf8mb4_swedish_ci         232  
      utf8mb4_turkish_ci         233  
      utf8mb4_czech_ci           234  
      utf8mb4_danish_ci          235  
      utf8mb4_lithuanian_ci      236  
      utf8mb4_slovak_ci          237  
      utf8mb4_spanish2_ci        238  
      utf8mb4_roman_ci           239  
      utf8mb4_persian_ci         240  
      utf8mb4_esperanto_ci       241  
      utf8mb4_hungarian_ci       242  
      utf8mb4_sinhala_ci         243  
      
      ***/
}
package test2;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;

import mysql.ClientRequestType;
import mysql.MysqlAnalyse;
import mysql.Util;

/**
 * 這是測試類 
 * @author shanl
 *
 */
public class Test4 {
    public static void main(String[] args){
//      t1();
//      t2();
//      t3();
//      t4();
//      t5();
//      t6();
//      t7();
        t8();
    }

    /**
     * 調用MysqlAnlyse進行分析
     */
    static void t8(){
        long packLen = 0;   //3byte
        long number = 0; //1byte
        long compress = 0;   //3byte

        File srcDir = new File("e://a//2");
        File compressFile = new File(srcDir,"fc_103533_0.out.compress.3"); //uncompress
//      File compressFile = new File(srcDir,"fc_103533_0.out.compress.2"); //uncompress
//      File compressFile = new File(srcDir,"fc_103533_0.out.compress.1"); //compress
//      File compressFile = new File(srcDir,"fc_103533_0.out.decompress"); //non-compress

        int readLen = 0;
        byte[] buff = new byte[1024*4];

        try {
            FileInputStream fin = new FileInputStream(compressFile);
            readLen = fin.read(buff);         
            fin.close();
        } catch (Exception e) {     
            e.printStackTrace();
        }

        try{
            MysqlAnalyse anly = new MysqlAnalyse();
            anly.setProperty("compress", true);
            anly.parse(buff, 0, readLen);

            System.out.println(anly.getRequestType());
            System.out.println(anly.getSql());
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    static void t7(){     
        byte[] capability_flags_lower = {
                (byte) 0xff,(byte) 0xf7
        };
        byte[] capability_flags_upper = {
                (byte) 7f,(byte) 0x80
        };
//      byte[] bys = {
//              capability_flags_upper[1],capability_flags_upper[0],
//              capability_flags_lower[1],capability_flags_lower[0]
//      };
//      byte[] bys = {
//              capability_flags_lower[0],capability_flags_lower[1],
//              capability_flags_upper[0],capability_flags_upper[1],                
//      };      
        byte[] bys = {               
                capability_flags_upper[0],capability_flags_upper[1],
                capability_flags_lower[0],capability_flags_lower[1],
        };
//      byte[] bys = {
////                (byte) 0x85,(byte) 0xa6
//              (byte) 0xa5,(byte) 0xa6
//      };

        long capability_flags = bigBys2Uint32(bys,0,bys.length);
//      System.out.println(capability_flags);

        long compress_flag = 0x00000020;     
        long odbc_flag = 0x00000040;
        long l = capability_flags & compress_flag;
        System.out.println(l);
        System.out.println(compress_flag==l);
    }

    static void t6(){
        byte[] bys = "中".getBytes();
        long i32 = bigBys2Uint32(bys,0,bys.length);
        System.out.println(i32);
    }

    static void t5(){
        long packLen = 0;   //3byte
        long number = 0; //1byte
        long compress = 0;   //3byte

        File srcDir = new File("e://a//2");
        File compressFile = new File(srcDir,"fc_103533_0.out.compress.1"); //uncompress
//      File compressFile = new File(srcDir,"fc_103533_0.out.compress.2"); //compress


        int readLen = 0;
        byte[] buff = new byte[1024*4];

        try {
            FileInputStream fin = new FileInputStream(compressFile);
            readLen = fin.read(buff);         
            fin.close();
        } catch (Exception e) {     
            e.printStackTrace();
        }

        try{
            packLen = littleBys2Uint32(buff,0,3);
            number = littleBys2Uint32(buff,3,1);
            compress = littleBys2Uint32(buff,4,3);

            System.out.println("readLen: "+readLen);
            System.out.println("packLen: "+packLen);
            System.out.println("number: " +number);
            System.out.println("compress: "+compress);
        }catch(Exception e){
            e.printStackTrace();
        }

        //decompress
        long srcLen = 0;
        long srcReqType = 0;
        byte[] srcData = null;
        try{
            if(compress>0){
                byte[] decompressData = Util.decompress(buff,3+1+3,readLen-7);
                srcLen = Util.littleBys2Uint32(decompressData,0,4)-1;//-1去掉clientRequestType
                srcReqType = Util.littleBys2Uint32(decompressData, 4, 1);
                srcData = new byte[(int) srcLen];
                System.arraycopy(decompressData, 5, srcData, 0, (int)srcLen);//
            }else{
                srcLen = Util.littleBys2Uint32(buff,3+1+3,4)-1; //-1去掉clientRequestType              
                srcReqType = Util.littleBys2Uint32(buff, 3+1+3+4, 1);               
                srcData = new byte[(int) srcLen];
                System.arraycopy(buff, 3+1+3+4+1, srcData, 0, (int)srcLen);             
            }

            System.out.println("srcLen: "+srcLen);
            System.out.println("srcReqType: "+srcReqType);
            if((int)srcReqType==ClientRequestType.COM_QUERY){
                System.out.println("sql: "+new String(srcData));
            }else{
                System.out.println("non-sql request.");
            }

        }catch(Exception e){
            e.printStackTrace();
        }
    }

    static void t4(){
        byte[] bys = {
                (byte) 0xda,0x00,0x00,
        };
        byte[] bys1 = {
                0x00,0x00,(byte) 0xda,
        };

        System.out.println(littleBys2Uint32(bys,0,bys.length));
        System.out.println(bigBys2Uint32(bys1,0,bys1.length));
    }

    /**
     * Big-Endian字節數組轉uint32
     * @param bys
     * @param off
     * @param len
     * @return
     */
    static long bigBys2Uint32(byte[] bys,int off,int len){
        long uint32 = 0;
        for(int i=0,end=len-1,c=end; i<=end; i++,c--){
            uint32 |= (0xff&bys[off+i])<<(8*c);
        }
        return uint32;     
    }

    /**
     * Little-Endian字節數組轉uint32
     * @param bys
     * @param off
     * @param len
     * @return
     */
    static long littleBys2Uint32(byte[] bys,int off,int len){
        long uint32 = 0;
        for(int i=len-1; i>=0; i--){          
            uint32 |= (0xff&bys[off+i])<<(8*i);
        }
        return uint32;
    }

    static void t3(){
        short[] bys = {
                0xda,0x00,0x00,0x00
        };

        long uint32 = 0;
        for(int i=bys.length-1; i>=0; i--){           
            uint32 |= (0xff&bys[i])<<(8*i);
        }

        System.out.println(uint32);
//      System.out.println(0xff&0xda);
    }

    public static byte[] decompress(byte[] data, int off, int len) {  
        byte[] output = new byte[0]; 
        Inflater decompresser = new Inflater();  
        decompresser.reset();         
//      decompresser.setInput(data);
        decompresser.setInput(data, off, len);        
          
        ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);  
        try {  
            byte[] buf = new byte[1024];  
            while (!decompresser.finished()) {  
                int i = decompresser.inflate(buf);  
                o.write(buf, 0, i);  
            }  
            output = o.toByteArray();  
        } catch (Exception e) {  
            output = data;  
            e.printStackTrace();  
        } finally {  
            try {  
                o.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
  
        decompresser.end();  
        return output;  
    }

    public static void decompress(byte[] data, int off, int len,OutputStream out) throws Exception{
        Inflater decompresser = new Inflater();  
        decompresser.reset();
        decompresser.setInput(data, off, len);
        byte[] buf = new byte[1024];

        while(!decompresser.finished()){
            int i = decompresser.inflate(buf);
            out.write(buf, 0, i);
            out.flush();
        }
    }

    static void t2(){
        File recordDir = new File("e://a//2");
        String srcFile = "fc_103533_0.out";
        File cf = new File(recordDir,srcFile+".compress");
//      File cf1 = new File(recordDir,"fc_103533_0.out.compress.1");
        File df = new File(recordDir,srcFile+".decompress");
        int readLen = 0;
        byte[] buff = new byte[1024*4];

        try {
            FileInputStream fin = new FileInputStream(cf);          
            readLen = fin.read(buff);
            fin.close();            
        } catch (Exception e) {     
            e.printStackTrace();
        }

//      try{
//          FileOutputStream fout = new FileOutputStream(cf1);
//          fout.write(buff,7,readLen-7);
//          fout.close();
//      }catch(Exception ex){
//          ex.printStackTrace();
//      }

        try{
            FileOutputStream fout = new FileOutputStream(df);
            decompress(buff,7,readLen-7,fout);
            fout.close();
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    static final SimpleDateFormat sdf = new SimpleDateFormat("[HH:mm:ss]");
    static final SimpleDateFormat fsdf = new SimpleDateFormat("HHmmss");  
    /**
     * 簡單的代理,主要用于本地存儲通信字節
     */
    static void t1(){
        File recordDir = new File("e://a//2");
        String tsip = "192.168.2.182";       
        int tsport = 3306;
        int listenPort = 3306;
        ServerSocket ss = null;      
        Socket fcsocket = null;
        Socket tssocket = null;
        int readTimeout = 1000*60*5;

        try{
            System.out.println("listen port:"+listenPort);
            ss = new ServerSocket(listenPort);
            for(int i=0;;i++){             
                fcsocket = ss.accept();
                fcsocket.setSoTimeout(readTimeout);
                System.out.println("new connected "+i);
                tssocket = new Socket(tsip,tsport);
                tssocket.setSoTimeout(readTimeout);             
                String fname_padding = fsdf.format(new Date())+"_"+i+".out";
                new Recording(fcsocket,tssocket,new File(recordDir,"fc_"+fname_padding)).start();
                new Recording(tssocket,fcsocket,new File(recordDir,"ts_"+fname_padding)).start();
            }
        }catch(Exception ex){          
        }
    }

    static class Recording extends Thread{
        Socket fcsocket = null;
        Socket tssocket = null;
        File recordFile = null;

        public Recording(Socket from,Socket to,File file){
            this.fcsocket = from;
            this.tssocket = to;
            this.recordFile = file;
        }       

        public void run(){
            InputStream fcin = null;
            OutputStream tsout = null;
            int readLen = 0;
            byte[] buff = new byte[1024*4];
            FileOutputStream fileOut = null;

            try{
                recordFile.createNewFile();
                fcin = fcsocket.getInputStream();
                tsout = tssocket.getOutputStream();               
                fileOut = new FileOutputStream(recordFile);              
            }catch(Exception ex){
                try { fileOut.close(); } catch (IOException e) { }
                try { fcsocket.close(); } catch (IOException e) { }
                try { tssocket.close(); } catch (IOException e) { }
                return;
            }           

            for(;;){
                try{
                    readLen = fcin.read(buff);
                    tsout.write(buff,0,readLen);
                    tsout.flush();

                    fileOut.write(sdf.format(new Date()).getBytes());
                    fileOut.write(buff,0,readLen);
                    fileOut.flush();
                }catch(SocketTimeoutException ste){
                    continue;
                }catch(Exception ex){      
                    break;
                }
            }

            try{fileOut.close();}catch(Exception ex){}
        }

    }
}


 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!