import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket; public class ServerTest { private ServerSocket ss;
private Socket socket;
PrintWriter out;
private int i = 0; public ServerTest() {
try {
ss = new ServerSocket(7838);
while (true) {
System.out.println(0);
socket = ss.accept();
ss.setSoTimeout(50000);
byte[] b = new byte[1024];
b[0] = (byte) 0x55;
b[1] = (byte) 0xAA;
b[2] = (byte) 0x01;
b[3] = (byte) 0x00;
b[4] = (byte) 0x00;
b[5] = (byte) 0x00;
b[6] = (byte) 0x00;
b[7] = (byte) 0x00;
b[8] = (byte) 0x00;
b[9] = (byte) 0x00;
b[10] = (byte) 0x00;
b[11] = (byte) 0x00;
b[12] = (byte) 0x00;
b[13] = (byte) 0x00;
b[14] = (byte) 0x00;
b[15] = (byte) 0x00;
b[16] = (byte) 0x00; InputStream socketReader = socket.getInputStream();
OutputStream socketWriter = socket.getOutputStream();
socketWriter.write(b);
System.out.println("OK");
socketWriter.flush();
i = i + 1;
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
new ServerTest();
}
}
上面是我百度的JAVA socket 发送十六进制数据的代码,通过这个思路,我进行了一些抽象:
 
因为我需要模拟多个报文,每个报文都用字节流拆分比较费时间,从网上查询到把一个字符串直接拆分成字节流的方法:
 public class socketWriter {
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
// toUpperCase将字符串中的所有字符转换为大写
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
// toCharArray将此字符串转换为一个新的字符数组。
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
//charToByte返回在指定字符的第一个发生的字符串中的索引,即返回匹配字符
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
}

因为我需要对输入流的数据进行解析,所以写了一个公共方法,把字节流转换成字符串:

// 字节的转换
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. 计算包体长度

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

(转)JAVA socket 进行十六进制报文交互测试的更多相关文章

  1. java socket发送xml报文

    ServerRun.java import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; pub ...

  2. java socket报文通信(一)socket的建立

    java socket报文通信(一) socket的建立  今天来和大家分享一下java中如何使用socket进行通信.先来啰嗦两句,看看Tcp/ip和udp: TCP是Transfer Contro ...

  3. 实现服务器和客户端数据交互,Java Socket有妙招

    摘要:在Java SDK中,对于Socket原生提供了支持,它分为ServerSocket和Socket. 本文分享自华为云社区<Java Socket 如何实现服务器和客户端数据交互>, ...

  4. JAVA Socket超时浅析

    JAVA Socket超时浅析 套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的"终端".针对一个特定的连接,每台机器上都有一个"套接字&q ...

  5. [ 转载]JAVA Socket超时浅析

    JAVA Socket超时浅析 转载自 http://blog.csdn.net/sureyonder/article/details/5633647 套接字或插座(socket)是一种软件形 式的抽 ...

  6. JAVA Socket超时浅析(转)

    套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”.针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”.JAVA有两个基于数据流 ...

  7. 关于java socket(转)

    1. 关于new Socket()中参数的理解 Server端: 调用ServerSocket serverSocket = new ServerSocket(1287,2);后Server端打开了指 ...

  8. Java Socket与操作系统的关系

    Socket与操作系统有什么关系呢?请细读下文 简介 TCP简介 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议 ...

  9. 关于java socket

    1. 关于new Socket()中参数的理解 Server端: 调用ServerSocket serverSocket = new ServerSocket(1287,2);后Server端打开了指 ...

随机推荐

  1. leetcode 135分发糖果

    这是一道hard题,不好想,但最后还是想出来了,私以为还是根据一些思想方法自己想出来做法印象比较深刻,其次看人家的做法思想自己写代码,其次看代码理解默写,其次直接抄代码: 首先,给每个孩子都发一个糖果 ...

  2. Grunt打包Electron,生成exe的安装包

    在之前的博客:3.electron打包生成exe文件 我们已经得到了electron打包好的应用了,目录如下,但是我们如何整合成一个安装程序,发给客户使用呢? 我们可以使用grunt-electron ...

  3. Upload 上传

    通过点击或者拖拽上传文件 点击上传 通过 slot 你可以传入自定义的上传按钮类型和文字提示.可通过设置limit和on-exceed来限制上传文件的个数和定义超出限制时的行为.可通过设置before ...

  4. Tensorflow所遇坑

    TensorFlow问题: 1.FLAGS._parse_flags()报错AttributeError:_parse_flags 解决: 因为TensorFlow的版本问题了,TensorFlow版 ...

  5. Java关键字之static的典型用法分析

    static关键字是java中非常重要的一个关键字,用的好的话可以提高程序的运行性能,优化程序结构.接下来我们来总结一下static关键字及其用法.1.static变量 static变量也称作静态变量 ...

  6. 转·c语言函数指针的理解与使用

    原文出处:https://www.cnblogs.com/haore147/p/3647262.html 1.函数指针的定义 顾名思义,函数指针就是函数的指针.它是一个指针,指向一个函数.看例子: 1 ...

  7. 给nginx添加客户端的请求最大单文件限制

    在nginx.conf中添加如下. client_max_body_size 10m; #允许客户端请求的最大单文件字节数 client_body_buffer_size 128k; #缓冲区代理缓冲 ...

  8. P2429 【制杖题】

    这题目名字也是够了... emmmmmm为什么要用线筛??????不感觉很麻烦吗??????既然是智障制杖题,那么肯定要用很简单的算法啦~下面,我就提供一种非常便于理解的膜你算法~~~很明显,做了这题 ...

  9. firewalld防火墙简介

    1.防火墙 防火墙,其实就是一个隔离工具:工作于主机或者网络的边缘 对于进出本主机或者网络的报文根据事先定义好的网络规则做匹配检测, 对于能够被规则所匹配的报文做出相应处理的组件(这个组件可以是硬件, ...

  10. USACO4.3 Buy Low, Buy Lower【简单dp·高精度】

    如果没有方案数的话,这道题水的不得了,裸的最长下降子序列. 但是它有方案数,所以... 一个是方案数的求法: 设$f[i]$是以$a[i]$结尾的最长下降子序列的长度,可以$n^2$$dp$出答案 如 ...