最近在做一个项目时要测试TOMCAT和NIO的吞吐量,其实在网上有很大一批用来做测试的工具,也非常不错,但是我还是盟生了自已写一个测试用例,起初自是想针对本次项目的服务器进行测试,不过后再做的时候发现很多问题,比方说怎么样控制读包错误后再访问和写包错误后的再访还有就是服务器本身Socket的连接数是有限的,怎么样再服务器拒绝连接后的操作,拒绝后是否算一次请求等等.下面我把具体的思路讲一下吧~!(其实说到实现,我是写得非常烂的,贴出来只是为了交流一下,希望有大侠们能多指都一下).
对于我们来说一台机器只能用线程来模拟用户数,也就是一个用户就是一个线程.但是在我在做完后,发现在大批量用户处理请求时有时由于服务器的处理速度非常快时,可能线程启动的时间,比服务器把全部请求处理完的速度还要快,这样测出来的数据就很不准确了,比如说我们模拟1000个用户发送20000次请求数据.因为我们的线程是在一起动就进行数据的请求,当我们起动到第300个时就已经把这20000个数据都请求完毕了,这样其实,我们就只测到了并发300个用户的吞吐量,所以我们必须保证每一个线程都至少发送了一次以上的请求.于是我最后得到了二种方案,第一种就是起用平均制,也就是说归定每个用户发送多少请求.第二种就是猜用集体等待通知制.第一种我想大家都明白是怎么回事,我这里解释一下第二种吧,第二种是首先把线程全部起动,但不执行请求,而是全部挂起.等待主线程全部通知执行.(呵呵`!可能是比较笨的方法)最后我先择了第二种,因为我想要真实的模拟用户发送是不可能平均的....
接下来说一下,就是在整个测试程序中,我们可以用一种Keep-Alive方式和非Keep-Alive方式发送请求,这二种方式的性能差是非常大的,(Keep-Alive是说当开起一个Socket连接后,一个用户针对这个Socket是不关闭的,基一个Socket上不断连续的发送请求,而非Keep-Alive的方式就是每次请求都会有一个独立的Socket开启,其实大家都知道,请求响应的时间其本上是很小的,我们所花的时间都在Socket的连接上,所以Keep-Alive和非Keep-Alive的方式性能相差非常大)当我用Keep-Alive的方式做一个任务时又发现,当连接不间断的提出请求时,有由于请求过快,可能导致服务器数据响应错误.所以后来又修改了程序.好了废话也写了一堆了,呵呵,文笔不好,多见谅.~!下面把代码贴出来吧~!
LockObject.java
/** */
/**
* @author Administrator
*
* 锁对像,存放着所有需要数据同步的锁对像
*/
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
public
class
LockObject
...
{
public static byte[] taskNum = new byte[0]; //任务数量锁对像
public static byte[] responseError = new byte[0]; //响应错误
public static byte[] readError = new byte[0]; //读错误
public static byte[] writeError = new byte[0]; //写错误
public static byte[] succ = new byte[0]; //成功数
public static byte[] refuseError = new byte[0]; //拒绝数
}
GlobalObject.java
/** */
/**
* @author Administrator
*
* 存放全局对像的.
*/
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
public
class
GlobalObject
...
{
public static String Ipaddress = null; //测试服务器IP地址
public static int prot = 0; //测试服务器端口
public static int userNums = 0; //客户端模拟用户数
public static int alltaskNums = 0; //待测试的任务数
public static int responseError = 0; //响应错误数
public static int readError = 0; //读错误数
public static int writeError = 0; //写错误数
public static int succ = 0; //响应成功数
public static int refuseError = 0; //服务器拒绝错误
public static int taskNums = 0; //已完成的任务数
public static int responseByteNums =0; //测试服务器响应字节数
public static int KeepAliv = 1; //是否KeepAliv 默认是
public static String method = "POST"; //数据发送方式
}
GlobalMethod.java
/** */
/**
* @author Administrator
*
* 存放全局方法,主要是做命令检查与解析.还有字符串分隔的,呵呵~!
* 由于JDK1.4提供的字符串分隔性能较低,所以自已实现了一个
*/
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
public
class
GlobalMethod
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/** *//**
* 解析命令
* @param cmd 命令字符串
* @return 返回boolean当解析成功时返回true否则返回flase
*/
public static boolean parseCmd(String cmd)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
boolean result = true;
if( cmd.indexOf("=")>0 )
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
String[] cmdArray = GlobalMethod.split(cmd,'=');
if( cmdArray.length==2 )
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
result = true;
String tempCmd = cmdArray[0].toLowerCase();
if( tempCmd.equals("server")) //测试服务器IP地址
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
GlobalObject.Ipaddress = cmdArray[1];
}
else if( tempCmd.equals("prot") ) //测试服务器端口
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
try
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
GlobalObject.prot = Integer.parseInt(cmdArray[1]);
if( GlobalObject.prot<=0 || GlobalObject.prot>=65535 )
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
System.out.println("protError");
result = false;
}
}
catch(NumberFormatException e)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
System.out.println("protError");
result = false;
}
}
else if( tempCmd.equals("users") ) //并发用户数
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
try
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
GlobalObject.userNums = Integer.parseInt(cmdArray[1]);
if( GlobalObject.userNums<=0