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