(转)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

相关文章
相关标签/搜索