浅谈配置元件之TCP取样器配置/TCP取样器
1.引言
在进行网络性能测试时,TCP取样器配置和TCP 取样器(TCP Sampler)是两个重要的组件,他们允许用户直接发送和接收TCP 数据包,这对于测试服务器的TCP 连接处理能力、模拟特定的TCP 交互场景非常有用。本文档将详细介绍如何在JMeter中配置和使用TCP 取样器配置和TCP取样器使用,因为两者基本一样,所以两个放在一起讲解。
2.添加TCP 取样器配置/TCP 取样器
添加TCP取样器配置
- 新建线程组:首先,在测试计划中右击,选择"添加" > "Threads(Users)" > "线程组(Thread Group)",添加一个线程组
- 添加TCP 取样器配置:在刚刚创建的线程组内,右击选择"添加" > "配置元件" > "TCP 取样器配置(TCP Sampler Config)"。
添加TCP取样器 - 新建线程组:首先,在测试计划中右击,选择"添加" > "Threads(Users)" > "线程组(Thread Group)",添加一个线程组
- 添加TCP 取样器:在刚刚创建的线程组内,右击选择"添加" > "取样器(Sampler)" > "TCP 取样器(TCP Sampler)"。
3.配置TCP 取样器
TCP 取样器的配置界面提供了多个参数,以满足不同的测试需求:
● TCPCllient classname:
TCP Sampler提供了3个报文编码类型的实现,分别是
1.org.apache.jmeter.protocol.tcp.sampler. TCPClientImp
2.org.apache.jmeter.protocol.tcp.sampler. BinaryTCPClientImpl
3.org.apache.jmeter.protocol.tcp.sampler. LengthPrefixedBinaryTCPClientImpl
1)TCPClientImpl以文本编辑器中所编辑的纯文本为内容进行发送。
2)BinaryTCPClientImpl以文本编辑器中所编辑的16进制字符(hex)内容为基础转换为二进制的
字节内容进行发送。
3)LengthPrefixedBinaryTCPClientImpl在BinaryTCPClientImpl基础上默认以发送内容的长度为
字节前缀进行填充。
案例说明的时候会根据不同的情况进行举例说明。
● 服务器名称或IP:输入目标服务器的域名或IP地址。
● 端口号:指定服务器上监听的TCP端口。
● 超时连接:与服务器套接字应用连接超时时间(毫秒)
● 超时时间:响应超时时间(毫秒),这个值的设置跟End of line(EOL) byte value有关系,如果End of line(EOL) byte value中的值设置不正确,会导致JMeter一直在等待无法结束,但是如果指定了Response Timeout这个值的话,在到达这个值的时候就关闭连接
● 重用连接(Re-use connection):勾选后,将在同一个线程内重用TCP连接,对于需要多次交互的测试场景非常有用。
● 关闭连接:测试结束后是否关闭连接。
● 设置无延迟:是否需要使用该选项,需要跟实际的业务情况结合
● SO_LINGER:该配置项用于控制在关闭连接之前是否要等待缓冲区中的数据发送完成。如果SO_LINGER选项指定了值,则在得到关闭连接的请求之后还会等待指定的秒数以完成缓冲区中数据的发送,在指定的SO_LINGER秒数完成后,关闭连接。因此,如果你把该选项设置成0,那么所有连接在收到关闭连接的时候都会立即关闭,避免产生很多处于TIME_WAIT状态的套接字。
● End of line(EOL) byte value:响应数据的最后2位,转换为10进制的值。取值区间[-128,127]。
● 要发送的文本:在此处输入要发送到服务器的数据。根据协议和需求,这可以是任何文本或二进制数据。
4.案例说明
情况1:TCPClientImp模式
- 后端测试代码如下
java
package com.test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class tcp {
public static void main(String[] args) throws Exception {
// 监听的端口号
int portNumber = 9002;
// 创建 ServerSocket 对象
ServerSocket serverSocket = new ServerSocket(portNumber);
System.out.println("等待客户端连接...");
while (true) {
// 接受客户端的连接请求
Socket client = serverSocket.accept();
System.out.println("客户端已连接,IP地址:" + client.getInetAddress().getHostAddress());
// 创建用于读取客户端发送的数据的输入流
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
System.out.println(in.readLine());
// 创建用于向客户端发送数据的输出流
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
out.println("hello Client");
out.flush(); // 刷新缓冲区,保证数据已被发送
// 关闭连接
in.close();
out.close();
client.close();
}
}
}
TCPCllient classname选择TCPClientImp,jmeter.properties中设置为tcp.handler=TCPClientImpl,服务器名称或IP设置127.0.0.1,端口号设置9002,要发送的文本设置为{"a": "b","c": "d"},其他默认
运行脚本,查看结果树,在响应数据的Response Body中可以看到信息:hello Client
情况2:BinaryTCPClientImpl模式
- 后端测试代码如下
java
package com.test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class tcp {
public static void main(String[] args) throws Exception {
// 监听的端口号
int portNumber = 9002;
// 创建 ServerSocket 对象
ServerSocket serverSocket = new ServerSocket(portNumber);
System.out.println("等待客户端连接...");
while (true) {
// 接受客户端的连接请求
Socket client = serverSocket.accept();
System.out.println("客户端已连接,IP地址:" + client.getInetAddress().getHostAddress());
// 创建用于读取客户端发送的数据的输入流
InputStream inputStream = client.getInputStream();
// 读取数据
byte[] buffer = new byte[1024];
int bytesRead;
StringBuilder data = new StringBuilder();
while ((bytesRead = inputStream.read(buffer)) != -1) {
// 将读取到的数据转换为字符串并添加到data中
data.append(new String(buffer, 0, bytesRead));
break;
}
System.out.println("接收到的数据:\n" + data.toString());
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
out.println("OK");
out.flush(); // 刷新缓冲区,保证数据已被发送
// 关闭连接
out.close();
client.close();
}
}
}
TCPCllient classname选择BinaryTCPClientImpl,jmeter.properties中设置为tcp.handler=BinaryTCPClientImpl,服务器名称或IP设置127.0.0.1,端口号设置9002,要发送的文本设置为697427732074696d6520746f20706c61792e,使用在线工具(https://www.sojson.com/hexconvert/16to10.html)可以获取范围该内容为:it's time to play.行尾(EOL)字节值使用10,其他默认运行脚本,查看结果树,在响应数据的Response Body中可以看到信息:4f4b0d0a,该数据进行翻译以后即为测试代码中OK的字符。
情况3:LengthPrefixedBinaryTCPClientImpl模式
根据情况2,发现发送内容无区别,但是在响应数据中可以看到不一样。
情况4:Re-use connection模式
后端测试代码如下
java
package com.test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class tcp {
public static void main(String[] args) throws Exception {
// 监听的端口号
int portNumber = 9002;
// 创建 ServerSocket 对象
ServerSocket serverSocket = new ServerSocket(portNumber);
System.out.println("等待客户端连接...");
while (true) {
// 接受客户端的连接请求
Socket client = serverSocket.accept();
System.out.println("客户端已连接,IP地址:" + client.getInetAddress().getHostAddress());
int remotePort = client.getPort();
// 创建用于读取客户端发送的数据的输入流
System.out.println("remotePort:" + remotePort);
InputStream inputStream = client.getInputStream();
// 读取数据
byte[] buffer = new byte[1024];
int bytesRead;
StringBuilder data = new StringBuilder();
while ((bytesRead = inputStream.read(buffer)) != -1) {
// 将读取到的数据转换为字符串并添加到data中
data.append(new String(buffer, 0, bytesRead));
break;
}
System.out.println("接收到的数据:\n" + data.toString());
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
out.println("OK");
out.flush(); // 刷新缓冲区,保证数据已被发送
// 关闭连接
out.close();
client.close();
}
}
}
主要就是将关闭连接的代码取消,并且将线程组中的循环次数设置为2
未勾选Re-use connection,未勾选关闭连接
- 当我们未勾选的时候,进行TCP测试,可以看到java后台打印的信息如下
xml
等待客户端连接...
客户端已连接,IP地址:10.33.123.18
remotePort:1066
接收到的数据:
it's time to play.
客户端已连接,IP地址:10.33.123.18
remotePort:1067
接收到的数据:
it's time to play.
勾选Re-use connection,未勾选关闭连接
- 当我们未勾选的时候,进行TCP测试,可以看到java后台打印的信息如下
xml
客户端已连接,IP地址:10.33.123.18
remotePort:27770
接收到的数据:
it's time to play.
勾选Re-use connection,勾选关闭连接
- 当我们勾选的时候,在未测试TCP时,我们首先看下当前在只启动后台的情况下,TCP的监听情况
xml
客户端已连接,IP地址:10.33.123.18
remotePort:13723
接收到的数据:
it's time to play.
客户端已连接,IP地址:10.33.123.18
remotePort:13724
接收到的数据:
it's time to play.
情况5:超时(毫秒):连接
超时(毫秒)中将连接设置为1,即1毫秒内需要建立连接,否则超时,其他参数不变,进行TCP测试,可以在查看结果树中看到如下结果:
xml
Error Count: 1
Data type ("text"|"bin"|""):
Response code: 500
Response message: java.net.SocketTimeoutException
情况6:超时(毫秒):响应
超时(毫秒)中将响应设置为1,即1毫秒内需要建立连接,否则超时,其他参数不变,进行TCP测试,可以在查看JMeter日志中看到如下结果:
xml
Caused by: java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method) ~[?:1.8.0_101]
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) ~[?:1.8.0_101]
at java.net.SocketInputStream.read(SocketInputStream.java:170) ~[?:1.8.0_101]
at java.net.SocketInputStream.read(SocketInputStream.java:141) ~[?:1.8.0_101]
at java.net.SocketInputStream.read(SocketInputStream.java:127) ~[?:1.8.0_101]
at org.apache.jmeter.protocol.tcp.sampler.BinaryTCPClientImpl.read(BinaryTCPClientImpl.java:134) ~[ApacheJMeter_tcp.jar:5.1.1 r1855137]
... 6 more
5.总结
通过上述步骤,你可以有效地配置和利用JMeter的TCP 取样器来进行TCP层面的性能和功能测试。无论是简单的连接测试,还是复杂的交互协议模拟,TCP 取样器都提供了强大的支持。记得在实际测试前,充分理解你的测试目标,并根据需要调整取样器的配置选项,以确保测试的有效性和准确性。