(轉)JAVA socket 進行十六進制報文交互測試

 1 import java.io.IOException;  2 import java.io.InputStream;  3 import java.io.OutputStream;  4 import java.io.PrintWriter;  5 import java.net.ServerSocket;  6 import java.net.Socket;  7   
 8 public class ServerTest {  9   
10     private ServerSocket ss; 11     private Socket socket; 12  PrintWriter out; 13     private int i = 0; 14   
15     public ServerTest() { 16         try { 17             ss = new ServerSocket(7838); 18             while (true) { 19                 System.out.println(0); 20                 socket = ss.accept(); 21                 ss.setSoTimeout(50000); 22                 byte[] b = new byte[1024]; 23                 b[0] = (byte) 0x55; 24                 b[1] = (byte) 0xAA; 25                 b[2] = (byte) 0x01; 26                 b[3] = (byte) 0x00; 27                 b[4] = (byte) 0x00; 28                 b[5] = (byte) 0x00; 29                 b[6] = (byte) 0x00; 30                 b[7] = (byte) 0x00; 31                 b[8] = (byte) 0x00; 32                 b[9] = (byte) 0x00; 33                 b[10] = (byte) 0x00; 34                 b[11] = (byte) 0x00; 35                 b[12] = (byte) 0x00; 36                 b[13] = (byte) 0x00; 37                 b[14] = (byte) 0x00; 38                 b[15] = (byte) 0x00; 39                 b[16] = (byte) 0x00; 40   
41                 InputStream socketReader = socket.getInputStream(); 42                 OutputStream socketWriter = socket.getOutputStream(); 43  socketWriter.write(b); 44                 System.out.println("OK"); 45  socketWriter.flush(); 46                 i = i + 1; 47  out.flush(); 48  } 49         } catch (IOException e) { 50  e.printStackTrace(); 51  } 52  } 53   
54     public static void main(String[] args) { 55         new ServerTest(); 56  } 57 }
上面是我百度的JAVA socket 發送十六進制數據的代碼,經過這個思路,我進行了一些抽象:
 
由於我須要模擬多個報文,每一個報文都用字節流拆分比較費時間,從網上查詢到把一個字符串直接拆分紅字節流的方法:
 1 public class socketWriter {  2     public static byte[] hexStringToBytes(String hexString) {  3         if (hexString == null || hexString.equals("")) {  4             return null;  5  }  6         // toUpperCase將字符串中的全部字符轉換爲大寫 
 7         hexString = hexString.toUpperCase();  8         int length = hexString.length() / 2;  9         // toCharArray將此字符串轉換爲一個新的字符數組。 
10         char[] hexChars = hexString.toCharArray(); 11         byte[] d = new byte[length]; 12         for (int i = 0; i < length; i++) { 13             int pos = i * 2; 14             d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); 15  } 16         return d; 17  } 18     //charToByte返回在指定字符的第一個發生的字符串中的索引,即返回匹配字符 
19     private static byte charToByte(char c) { 20         return (byte) "0123456789ABCDEF".indexOf(c); 21  } 22 }

由於我須要對輸入流的數據進行解析,因此寫了一個公共方法,把字節流轉換成字符串:java

// 字節的轉換 
public class ByteUtil { //將字節數組轉換爲short類型,即統計字符串長度 
    public static short bytes2Short2(byte[] b) { short i = (short) (((b[1] & 0xff) << 8) | b[0] & 0xff); return i; } //將字節數組轉換爲16進制字符串 
    public static String BinaryToHexString(byte[] bytes) { String hexStr = "0123456789ABCDEF"; String result = ""; String hex = ""; for (byte b : bytes) { hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4)); hex += String.valueOf(hexStr.charAt(b & 0x0F)); result += hex + " "; } return result; } } 

在模擬客戶端發送報文中去調用該方法便可,則能夠實現只須要傳入字符串,完成客戶端與服務器的交互,並完成輸入流的字符串轉換,數組

代碼以下:服務器

import java.net.Socket; import Base.ByteUtil; import Base.socketWriter; import java.io.InputStream; import java.io.OutputStream; public class ClientLaunch { // 這個客戶端鏈接到地址爲xxx.xxx.xxx.xxx的服務器,端口爲10020,併發送16進制到服務器,而後接受服務器的返回信息,最後結束會話。 // 客戶端,使用Socket對網絡上某一個服務器的某一個端口發出鏈接請求,一旦鏈接成功,打開會話;會話完成後,關閉Socket。客戶端不須要指定打開的端口,一般臨時的、動態的分配一個1024以上的端口。 
    public String Client(Socket socket, socketWriter s, InputStream socketReader, String strInput) { String strOutput = ""; try { //客戶端輸出流做爲服務器的輸入 
            OutputStream socketWriter = socket.getOutputStream(); socketWriter.write(s.hexStringToBytes(strInput)); socketWriter.flush(); Thread.sleep(1000); //服務器的輸出即爲客戶端的輸入,這裏主要是爲了把服務器輸出的字節流報文轉化成字符串,方便進行解析,最終測試報文的正確性 
            socketReader = socket.getInputStream(); //由於我測試的報文包含報文頭和報文體,這裏的字節數組長度37爲報文頭長度 
            byte[] temp = new byte[37]; int bytes = 0; /* read從輸入流socketReader中讀取temp(37)數量的字節數,並將它們存儲到緩衝區數組temp。實際讀取的字節數做爲一個整數37返回。 * 此方法塊,直到輸入數據可用,檢測到文件結束,或拋出異常。若是B的長度爲零,則沒有讀取字節數和返回0; * 不然,將有一個至少一個字節的嘗試。若是沒有可用的字節,由於流是在文件的結尾,值- 1返回;不然,至少一個字節被讀取和存儲到temp。 */ bytes = socketReader.read(temp); if (bytes != 37) { return null; } strOutput += ByteUtil.BinaryToHexString(temp); //讀取報文體的內容 
            byte[] array = new byte[2]; for (int i = 1; i < 3; i++) { array[i - 1] = temp[i]; } int let = ByteUtil.bytes2Short2(array); array = new byte[let]; bytes = socketReader.read(array); if (bytes != let) { return null; } strOutput += ByteUtil.BinaryToHexString(array); //把字符串中「 」去掉 
            strOutput = strOutput.replaceAll(" ", ""); } catch (Exception e) { e.printStackTrace(); } return strOutput; } } 

這樣就完成了報文數據傳送,以及讀取的基礎代碼,調用它們便可完成交互,如測試報文數據的處理:網絡

public class CardFlow { ClientLaunch cl = new ClientLaunch(); Socket socket; socketWriter socketWriter = new socketWriter(); InputStream socketReader; @Test public void cardFlow() throws Exception { // 創建 socket連接,鏈接服務器192.168.1.1:8080 
        socket = new Socket("192.168.1.1", "8080"); String charger="00000000136"; //登錄,經過驗證輸出報文中的響應報文是否爲 "000000",判斷是否登錄成功,其中loginInput爲輸出報文字符串 
        String loginInput="283400120001"+charger+"10002016112214151800000000321321233212FFFFFFFFFFFFFFFF00010201"; String outlogin = cl.Client(socket, socketWriter, socketReader, loginInput); Assert.assertEquals(outlogin.substring(30,36), "000000"); //心跳,經過驗證輸出報文中的響應報文是否爲 "000000",判斷是否交互成功 
        String heartbeatInput="283400130001"+charger+"1000201611221415180000"; String outheartbeat = cl.Client(socket, socketWriter, socketReader, heartbeatInput); Assert.assertEquals(outheartbeat.substring(30,36), "000000"); socket.close(); } } 

則完成socket報文交互測試的實現流程:多線程

1. 讀取協議配置併發

2. 替換可變長度和值框架

3. 計算包體長度socket

4. 包頭+包長度+包體+包尾工具

5. 創建到192.168.1.1:8080的 socket鏈接性能

6. 發送數據包

7. 等待接收返回數據包(超時)

8. 解析返回數據包

9. 獲得定位值1和定位值2(便於驗證)

 

該方法完成後,能夠進行基於協議的壓力測試:

針對頻繁請求和處理的協議(不頻繁默認無問題),自動生成多測試數據,多客戶端多線程長時間進行協議測試,不斷加壓,統計請求響應時間變化、失敗和成功的數據及比例,並收集服務器性能參數和資源消耗等數據(可自動出圖),手動檢查和數據結果分析。

 

附:通用自動化測試工具效果

1. 主體框架實現特定功能,高級語言完成,並開放大量實用API,且不斷增長和完善

2. 嵌套或封裝一種或多種腳本語言解析器,可以動態執行測試用例腳本,對Windows窗體、Web、代碼、接口、協議或性能等若干方面進行測試(擴展:錄製功能)

3. 流程完善,可以準確高效的解放人力和深刻測試,手工儘量少的參與或專一於測試用例腳本工做

4. 可擴展性強,可以遠程操控多個多種平臺(分佈集羣,經過網絡通訊、協議通訊等),可以並行調度執行,可配置可存儲,資源共享方便

5. 自動化框架工做:檢測新的版本-->下載、編譯、批量部署-->調用指定測試腳本執行測試-->郵件或消息通知QA測試結果報告路徑和發現的bug。

6. 手工工做:編寫修改測試腳本並上傳、收郵件校驗bug

相關文章
相關標籤/搜索