C 网页压力测试器
引言
<<独白>> 席慕蓉 节选一
把向你借来的笔还给你吧。
一切都发生在回首的刹那。
我的彻悟如果是缘自一种迷乱,那么,我的种种迷乱不也就只是因为一种彻悟?
在一回首间,才忽然发现,原来,我的一生的种种努力,不过只是为了周遭的人都对我满意而已。
为了要博得他人的称许与微笑,我战战兢兢地将自己套入所有的模式,所有的桎梏。
走到中途,才忽然发现,我只剩下一副模糊的面目,和一条不能回头的路。
把向你借来的笔还给你吧。
配乐 :
我在长大 : http://music.163.com/#/song?id=155977
不知疲倦的整夜码代码 像块石头一样滚来滚去
可是找不到家的方向
我在长大 / 我在长大 / 我在长大 / 我在长大
前言
我们先说一下,参照的东西和需要掌握的东西
具体参照
1. HTTP协议简单介绍 http://www.cnblogs.com/biyeymyhjob/archive/2012/07/28/2612910.html
这里需要掌握简单的Linux 操作,这里分享一个自己总结的socket入门基础文档.
2. socket 简单入门doc http://download.csdn.net/detail/wangzhione/9412538
到这里, 基本准备工作就完成了,那就搞起吧, 看看那些说起来很玄乎的工具是怎么简单实现的.顺带扯一点,
下面代码自己多看几遍写一遍,可以帮助你理解Linux中很多基础概念,例如 信号,多进程, 管道,socket,中断,
协议等.
正文
1.简单说一点格式
这里我们先看下面一段代码格式,来了解C接口设计中一些潜规则.
/*
* 这是一个对外的接口函数声明,
*相当于public
*/
extern int isbig(void); /*
* 这个接口也具备对外能力,但是省略了extern
*意图就是构建整个 *.h文件的时候需要用它,但是不希望用户用.
*属于 low level api, 内部接口集用,外部不推荐用,有点像protected
*/
int heoo(void); /*
* 这个是个内部声明或定义, 只能在当前接口集的内部使用,外部无法
*访问,相当于pirate
*/
static void* __run(void* arg);
定义部分简单说明一下.以前博文中说过,这里再简单说一次,编程和打游戏一样,要有好节奏,
要有好套路,这样打起来才顺.等同于实践可以总结出理论基础.前任要感谢.
/*
* 定义加声明,放在一块
*/
static int __run(void)
{
static union {
unsigned short _s;
unsigned char _cs[sizeof(unsigned short)];
} __ut = { };
return __ut._cs[] == ;
} /*
* 声明和定义分开
*/
extern void start(void);
//下面是定义部分
void
start(void)
{
puts("你好!");
}
套路很多,都是历代编程王者,开创的各大武功的起手式,各大定式都可以就看你想拜入那个门派,开始这个编程网游之旅.
2.说思路
经过上面简单格式介绍,这里就说一下思路. 关于 这篇博文,C 对网页的压力测试构建的思路.具体如下:
a. 拼接请求报文 , 解析
b. 发送请求报文 , 请求
c. 处理请求报文, 处理
d.总结请求报文, 输出统计
上面就是这次处理的主要流程, 多次请求采用的fork多个子进程
for(i=; i<cut; ++i){
pid = fork(); //狂开进程了
if(pid <= ){
sleep();//别让它太快完毕,父进程来不及收尸
break;//结束子进程继续
}
++rt;
}
关于父子进程通信采用 管道
//创建管道 进行测试, 代码比较杂,需要一些Linux基础知识,多练习
if(pipe(pfds)<-)
CERR_EXIT("pipe create is error!");
还有一个是通过信号处理超时问题
//默认全局标识, 控制开关
volatile int v_timer = 0; //闹钟信号,当它启动那一刻就表示可以退下了.
static void __alarm(int sig)
{
v_timer = 1;
}
后面我们就通过代码来说了,最好你写一遍,就明白容易了.扯一点,关于volatile 可以声明是为了方式编译器优化,导致代码死循环.
3.逐个实现
第一部分头文件,声明解析
首先观察下面前戏代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> //控制台打印错误信息, fmt必须是双引号括起来的宏
#ifndef CERR
#define CERR(fmt, ...) \
fprintf(stderr,"[%s:%s:%d][error %d:%s]" fmt "\r\n",\
__FILE__, __func__, __LINE__, errno, strerror(errno),##__VA_ARGS__) //检测并退出的宏
#define CERR_EXIT(fmt, ...) \
CERR(fmt, ##__VA_ARGS__), exit(EXIT_FAILURE) #endif/* !CERR */ // url长度限制 和 请求串长度限制
#define _INT_URL (1024)
#define _INT_REQ (2048)
//主机地址的最大长度
#define _INT_PORT (255)
//等待时间,在60s后就不在处理了
#define _INT_END (23) //简单结构
struct iport{
short port;
char ip[_INT_PORT];
}; //默认全局标识, 控制开关
volatile int v_timer = ; //闹钟信号,当它启动那一刻就表示可以退下了.
static void __alarm(int sig)
{
v_timer = ;
} /*
* 执行的主要方法,结果会通过写管道 wfd写入
*/
void bcore(struct iport* ips, const char* req, int wfd); /*
* 只接受完整请求
* 例如
* brequest("http://192.168.1.162:80/", ...) 或 http://www.baidu,com
* 通过url拼接请求串,并返回访问结构
*/
struct iport* brequst(const char* url, char rqs[], int len);
//请求主方法,客户端,返回开启的子进程数
int bench(int cut, const char* url, int wfd); /*
* 请求链接主机,根据ip或url
*
* host : url地址
* port : 请求的端口号
*/
int contweb(const char* host, int port);
CERR系列是一个帮助宏,简单打印错误信息. 技巧值得推荐使用.其中 _INT_END 表示每个子进程请求的时间长度(s).
感觉注释也挺详细的关于
//请求主方法,客户端,返回开启的子进程数
int bench(int cut, const char* url, int wfd);
主要开启多进程的,依次调用 breques解析url 和 调用 bcore 处理socket .
其中 contweb 是一个可以根据ip或主机地址url解析,链接主机.具体实现如下
/*
* 请求链接主机,根据ip或url
*
* host : url地址
* port : 请求的端口号
*/
int
contweb(const char* host, int port)
{
int sd;
in_addr_t ia;
struct sockaddr_in sa = { AF_INET };
struct hostent *hp; ia = inet_addr(host);
if(ia != INADDR_NONE)
memcpy(&sa.sin_addr, &ia, sizeof(ia));
else {
hp = gethostbyname(host);
if(hp < ){
CERR("gethostbyname %s error!", host);
return -;
}
memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
}
if((sd=socket(PF_INET, SOCK_STREAM, ))<){
CERR("socket SOCK_STREAM");
return sd;
} //连接主机
sa.sin_port = htons(port);
if(connect(sd, (struct sockaddr*)&sa, sizeof sa)<){
CERR("connect sd:%d error!", sd);
return -;
} return sd;
}
没有什么花哨的东西就是同步链接HTTP服务器, 如果传入的的host是url那么就调用 gethostbyname 获取到 请求
主机的sin_addr地址量.
扯一点,socket编程大部分也等同于业务代码,固定的套路固定的模式,写写也都会写了.但也挺麻烦了,随便一个简单的
完整的socket demo都4-5百行代码,写的手疼.封装也很麻烦.但是你理解了它的思路或套路,还是很容易上马提枪的.
第二部分各个,定义解析
首先代码可以优化,我写好后没优化了,就直接分享了.先看http协议解析代码如下
//通过url拼接请求串
struct iport*
brequst(const char* url, char rqs[], int len)
{
static struct iport __ips;
//请求的主机, 中间用的url, 临时数据
const char *hurl, *tmp;
char c;
int pt = ;//临时用的int变量 //简单检查参数检查,检查数组大小,url是否合法
if(len<_INT_REQ || !url || !*url || strlen(url)>_INT_URL)
CERR_EXIT("params url:%s, len[>=%d];%d error.", url, _INT_REQ, len);
//检测url是否是http请求的url,也比较简单,复杂检查要用正则表达式
hurl = strstr(url, "://");
if(!hurl || strncasecmp(url, "http", ))
CERR_EXIT("url is err [%s]!", url);
//简单初始化
memset(rqs, , len);
memset(&__ips, , sizeof __ips); //这种代码可以优化,用指针替代数组索引
strcat(rqs, "GET ");
hurl += ; //跳过 "://"指向下一个字符 //解析url 上是否有端口信息
tmp = index(hurl, ':');
if(tmp && tmp < index(hurl, '/')){
strncpy(__ips.ip, hurl, tmp - hurl);
//没有做安全检查
while((c=*++tmp)!='\0' && c!='/'){
if(c<='' && c>=''){
pt = *pt + c - '';
continue;
}
CERR_EXIT("url is error [%s].", url);
}
}
else{
pt = ; //默认端口
//这句话意思 是 将 www.baidu.com/ 其中/之前的地方写入到 ip[]中
strncpy(__ips.ip, hurl, strcspn(hurl, "/"));
}
__ips.port = pt; //将这些内容链接到rqs中
strcat(rqs, hurl + strcspn(hurl, "/"));
//采用HTTP1.1 协议
strcat(rqs, " HTTP/1.1\r\n");
//添加请求方
strcat(rqs, "User-Agent: Happy is good.\r\n");
//上面这样解析有点慢,最快的是整体for,但是更难维护
strcat(rqs, "Host: ");
strcat(rqs, __ips.ip);
strcat(rqs, "\r\n");
//拼接串最后,连接状态,完毕就关闭
strcat(rqs, "Connection: close\r\n");
//拼接空行, 上面可以优化
strcat(rqs, "\r\n"); //最终检测,是否字符串太长了
if(rqs[len-])
CERR_EXIT("get http too len!"); return &__ips;
}
主要思路是先检查 参数, 看 是否是 右边这样正则格式的串 "http.://.+/"
后面拼接结果截图如下:
更加详细关于HTTP协议解析的,可以参照我前面的连接,HTTP协议简单解析.
后面介绍的是有了请求串,怎么发送请求和处理请求,代码如下:
/*
* 执行的主要方法,结果会通过写管道 wfd写入
*/
void
bcore(struct iport* ips, const char* req, int wfd)
{
int srv, len, rlen;
int speed = , failed = , bytes = ;
FILE* fx;
char buf[_INT_REQ]; //先注册信号
if(SIG_ERR == signal(SIGALRM, __alarm))
CERR_EXIT("signal SIGALRM error!");
alarm(_INT_END); len = strlen(req);
for(;;){
if(v_timer){ //结束之前减一,认为成功过
if(failed>)
--failed;
break;
} srv = contweb(ips->ip, ips->port);
if(srv < ){
++failed;
continue;
}
//开始写入数据
if(len != write(srv, req, len)){
++failed;
close(srv);
continue;
}
//下面读取数据,v_timer标志是否超时,超时直接走
for(;!v_timer;){
rlen = read(srv, buf, _INT_REQ);
if(rlen < ){ //不考虑软中断了,有问题直接退出
++failed;
close(srv);
goto __bcore_exit; //退出结算
}
if(rlen == )//服务端关闭,结束读取
break;
bytes += rlen;
}
close(srv);
++speed;
} __bcore_exit:
//管道写入
fx = fdopen(wfd, "w");
if(NULL == fx)
CERR_EXIT("fdopen wfd:%d error!", wfd);
fprintf(fx,"%d %d %d\n", speed, failed, bytes);
fclose(fx);
}
中间发送了一个alarm延时发送SIGALRM 信号,还有一个信号容易混淆,是SIGCLD信号 子进程退出时候给父进程发送.
其中 fdopen 是将 Linux文件描述符和 C系统文件操作句柄转换.就是统计数据写入到管道中,管道 是 1进 0出.
最后还有个 开启多进程的函数代码
//请求主方法,客户端,返回开启子进程数
int
bench(int cut, const char* url, int wfd)
{
int i, rt = ;//rt 记录正常开启的进程
pid_t pid;
char req[_INT_REQ];
struct iport* ips; //这里初始化一些环境
ips = brequst(url, req, sizeof req);
puts("***********-----------------------------------------------------------***********");
puts(req); //打印数据
puts("***********-----------------------------------------------------------***********"); for(i=; i<cut; ++i){
pid = fork(); //狂开进程了
if(pid <= ){
sleep();//别让它太快完毕,父进程来不及收尸
break;//结束子进程继续
}
++rt;
}
if(pid < )
CERR_EXIT("child %d process create error!", i);
if(pid == ){ //子进程处理
bcore(ips, req, wfd);
exit(EXIT_SUCCESS);//子进程这里就结束了
}
//下面是父进程处理
return rt;
}
也比较好明白,先拼接请求串,再开启多进程挨个请求处理.
到这核心函数基本都完成了,总的业务构建请看下面
第三部分主函数逻辑构建
// 主函数业务,从这开始
int main(int argc, char* argv[])
{
int cut, len; //开启进程数量 和 读取scanf返回值
int pfds[];
FILE* fx;
int speed = , failed = , bytes = ; //简单检测
if((argc != ) || (cut = atoi(argv[]))<= || cut > USHRT_MAX){
CERR_EXIT(
"\r\nuage: ./webtest.out [cut] [url]"
"\r\n :=> ./webtest.out 19 http://www.baidu.com/"
);
} //创建管道 进行测试, 代码比较杂,需要一些Linux基础知识,多练习
if(pipe(pfds)<-)
CERR_EXIT("pipe create is error!"); //结果处理,开启指定多个进程,重新获取进程开启成功数
cut = bench(cut, argv[], pfds[]); //这里读取管道信息
fx = fdopen(pfds[], "r");
if(NULL == fx)
CERR_EXIT("fdopen pfds[0]:%d error.", pfds[]); //统计最后数据
setbuf(fx, NULL);
while(cut > ){
int s, f, b;
len = fscanf(fx, "%d %d %d", &s, &f, &b);
if(len < ){
CERR("fscnaf read error! len:%d.", len);
break;
}
speed += s;
failed += f;
bytes += b;
--cut;
}
fclose(fx);
close(pfds[]);
close(pfds[]); //输出统计结果
puts("***********-----------------------------------------------------------***********");
printf("Collect %.2f pages/min, %.2f kb/sec. Request %d sucess, %d failed.\n",
(speed+failed)*60.0f/_INT_END, bytes/1024.0f/_INT_END, speed, failed);
puts("***********-----------------------------------------------------------***********"); return ;
}
创建管道,调用多进程处理函数,汇总最后结果.注意一点是开启的管道最后需要自己关闭.(可能这里有坑),回头看一下,代码其实
还是比较基础的,主要用的就是Linux编程相关的知识点.
最后输出 每分钟请求的页面数, 每秒请求的bit流,请求成功多少次,请求失败多少次.
4.看案例结果
首选看下面一个操作图,先请求百度试试
最后统计结果是 每分钟请求了6357个界面左右,开启了23个子进程, 成功2414个,23个错误. 总的而言百度的分流确实不错,负载均衡强.
再来请求一个普通网站的截图
上面打印很多connect error,意思是很多进程请求链接失败,短时间大量链接导致对方服务器拒绝链接, 负载均衡差,
流量差不多,可能和网速有关,请求界面数挺多的这个界面不错,可能是纯静态的. 对于详细查看为什么失败,可以在记录 failed++的时候打印日志看看,
这里就这样了. 麻雀虽小,能用就好. 完整测试 demo 如下
webtest.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> //控制台打印错误信息, fmt必须是双引号括起来的宏
#ifndef CERR
#define CERR(fmt, ...) \
fprintf(stderr,"[%s:%s:%d][error %d:%s]" fmt "\r\n",\
__FILE__, __func__, __LINE__, errno, strerror(errno),##__VA_ARGS__) //检测并退出的宏
#define CERR_EXIT(fmt, ...) \
CERR(fmt, ##__VA_ARGS__), exit(EXIT_FAILURE) #endif/* !CERR */ // url长度限制 和 请求串长度限制
#define _INT_URL (1024)
#define _INT_REQ (2048)
//主机地址的最大长度
#define _INT_PORT (255)
//等待时间,在60s后就不在处理了
#define _INT_END (23) //简单结构
struct iport{
short port;
char ip[_INT_PORT];
}; //默认全局标识, 控制开关
volatile int v_timer = ; //闹钟信号,当它启动那一刻就表示可以退下了.
static void __alarm(int sig)
{
v_timer = ;
} /*
* 执行的主要方法,结果会通过写管道 wfd写入
*/
void bcore(struct iport* ips, const char* req, int wfd); /*
* 只接受完整请求
* 例如
* brequest("http://192.168.1.162:80/", ...) 或 http://www.baidu,com
* 通过url拼接请求串,并返回访问结构
*/
struct iport* brequst(const char* url, char rqs[], int len);
//请求主方法,客户端,返回开启的子进程数
int bench(int cut, const char* url, int wfd); /*
* 请求链接主机,根据ip或url
*
* host : url地址
* port : 请求的端口号
*/
int contweb(const char* host, int port); // 主函数业务,从这开始
int main(int argc, char* argv[])
{
int cut, len; //开启进程数量 和 读取scanf返回值
int pfds[];
FILE* fx;
int speed = , failed = , bytes = ; //简单检测
if((argc != ) || (cut = atoi(argv[]))<= || cut > USHRT_MAX){
CERR_EXIT(
"\r\nuage: ./webtest.out [cut] [url]"
"\r\n :=> ./webtest.out 19 http://www.baidu.com/"
);
} //创建管道 进行测试, 代码比较杂,需要一些Linux基础知识,多练习
if(pipe(pfds)<-)
CERR_EXIT("pipe create is error!"); //结果处理,开启指定多个进程,重新获取进程开启成功数
cut = bench(cut, argv[], pfds[]); //这里读取管道信息
fx = fdopen(pfds[], "r");
if(NULL == fx)
CERR_EXIT("fdopen pfds[0]:%d error.", pfds[]); //统计最后数据
setbuf(fx, NULL);
while(cut > ){
int s, f, b;
len = fscanf(fx, "%d %d %d", &s, &f, &b);
if(len < ){
CERR("fscnaf read error! len:%d.", len);
break;
}
speed += s;
failed += f;
bytes += b;
--cut;
}
fclose(fx);
close(pfds[]);
close(pfds[]); //输出统计结果
puts("***********-----------------------------------------------------------***********");
printf("Collect %.2f pages/min, %.2f kb/sec. Request %d sucess, %d failed.\n",
(speed+failed)*60.0f/_INT_END, bytes/1024.0f/_INT_END, speed, failed);
puts("***********-----------------------------------------------------------***********"); return ;
} /*
* 请求链接主机,根据ip或url
*
* host : url地址
* port : 请求的端口号
*/
int
contweb(const char* host, int port)
{
int sd;
in_addr_t ia;
struct sockaddr_in sa = { AF_INET };
struct hostent *hp; ia = inet_addr(host);
if(ia != INADDR_NONE)
memcpy(&sa.sin_addr, &ia, sizeof(ia));
else {
hp = gethostbyname(host);
if(hp < ){
CERR("gethostbyname %s error!", host);
return -;
}
memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
}
if((sd=socket(PF_INET, SOCK_STREAM, ))<){
CERR("socket SOCK_STREAM");
return sd;
} //连接主机
sa.sin_port = htons(port);
if(connect(sd, (struct sockaddr*)&sa, sizeof sa)<){
CERR("connect sd:%d error!", sd);
return -;
} return sd;
} //通过url拼接请求串
struct iport*
brequst(const char* url, char rqs[], int len)
{
static struct iport __ips;
//请求的主机, 中间用的url, 临时数据
const char *hurl, *tmp;
char c;
int pt = ;//临时用的int变量 //简单检查参数检查,检查数组大小,url是否合法
if(len<_INT_REQ || !url || !*url || strlen(url)>_INT_URL)
CERR_EXIT("params url:%s, len[>=%d];%d error.", url, _INT_REQ, len);
//检测url是否是http请求的url,也比较简单,复杂检查要用正则表达式
hurl = strstr(url, "://");
if(!hurl || strncasecmp(url, "http", ))
CERR_EXIT("url is err [%s]!", url);
//简单初始化
memset(rqs, , len);
memset(&__ips, , sizeof __ips); //这种代码可以优化,用指针替代数组索引
strcat(rqs, "GET ");
hurl += ; //跳过 "://"指向下一个字符 //解析url 上是否有端口信息
tmp = index(hurl, ':');
if(tmp && tmp < index(hurl, '/')){
strncpy(__ips.ip, hurl, tmp - hurl);
//没有做安全检查
while((c=*++tmp)!='\0' && c!='/'){
if(c<='' && c>=''){
pt = *pt + c - '';
continue;
}
CERR_EXIT("url is error [%s].", url);
}
}
else{
pt = ; //默认端口
//这句话意思 是 将 www.baidu.com/ 其中/之前的地方写入到 ip[]中
strncpy(__ips.ip, hurl, strcspn(hurl, "/"));
}
__ips.port = pt; //将这些内容链接到rqs中
strcat(rqs, hurl + strcspn(hurl, "/"));
//采用HTTP1.1 协议
strcat(rqs, " HTTP/1.1\r\n");
//添加请求方
strcat(rqs, "User-Agent: Happy is good.\r\n");
//上面这样解析有点慢,最快的是整体for,但是更难维护
strcat(rqs, "Host: ");
strcat(rqs, __ips.ip);
strcat(rqs, "\r\n");
//拼接串最后,连接状态,完毕就关闭
strcat(rqs, "Connection: close\r\n");
//拼接空行, 上面可以优化
strcat(rqs, "\r\n"); //最终检测,是否字符串太长了
if(rqs[len-])
CERR_EXIT("get http too len!"); return &__ips;
} /*
* 执行的主要方法,结果会通过写管道 wfd写入
*/
void
bcore(struct iport* ips, const char* req, int wfd)
{
int srv, len, rlen;
int speed = , failed = , bytes = ;
FILE* fx;
char buf[_INT_REQ]; //先注册信号
if(SIG_ERR == signal(SIGALRM, __alarm))
CERR_EXIT("signal SIGALRM error!");
alarm(_INT_END); len = strlen(req);
for(;;){
if(v_timer){ //结束之前减一,认为成功过
if(failed>)
--failed;
break;
} srv = contweb(ips->ip, ips->port);
if(srv < ){
++failed;
continue;
}
//开始写入数据
if(len != write(srv, req, len)){
++failed;
close(srv);
continue;
}
//下面读取数据,v_timer标志是否超时,超时直接走
for(;!v_timer;){
rlen = read(srv, buf, _INT_REQ);
if(rlen < ){ //不考虑软中断了,有问题直接退出
++failed;
close(srv);
goto __bcore_exit; //退出结算
}
if(rlen == )//服务端关闭,结束读取
break;
bytes += rlen;
}
close(srv);
++speed;
} __bcore_exit:
//管道写入
fx = fdopen(wfd, "w");
if(NULL == fx)
CERR_EXIT("fdopen wfd:%d error!", wfd);
fprintf(fx,"%d %d %d\n", speed, failed, bytes);
fclose(fx);
} //请求主方法,客户端,返回开启子进程数
int
bench(int cut, const char* url, int wfd)
{
int i, rt = ;//rt 记录正常开启的进程
pid_t pid;
char req[_INT_REQ];
struct iport* ips; //这里初始化一些环境
ips = brequst(url, req, sizeof req);
puts("***********-----------------------------------------------------------***********");
puts(req); //打印数据
puts("***********-----------------------------------------------------------***********"); for(i=; i<cut; ++i){
pid = fork(); //狂开进程了
if(pid <= ){
sleep();//别让它太快完毕,父进程来不及收尸
break;//结束子进程继续
}
++rt;
}
if(pid < )
CERR_EXIT("child %d process create error!", i);
if(pid == ){ //子进程处理
bcore(ips, req, wfd);
exit(EXIT_SUCCESS);//子进程这里就结束了
}
//下面是父进程处理
return rt;
}
编译代码如下
gcc -Wall -o webtest.out webtest.c
后面就需要大家尝试了,用的还凑合者.
光鲜的背后都是平凡.喜欢才是人这台机器的最好能源.
后记
错误是难免,欢迎指正交流,共同消磨有趣的时光. ( ^_^ )/~~拜拜
C 网页压力测试器的更多相关文章
- jmeter压力测试的简单实例+badboy脚本录制(一个简单的网页用户登录测试的结果)
JMeter的安装:在网上下载,在下载后的zip解压后,在bin目录下找到JMeter.bat文件,双击就可以运行JMeter. http://jmeter.apache.org/ 在使用jmeter ...
- 十个免费的Web压力测试工具
两天,jnj在本站发布了<如何在低速率网络中测试 Web 应用>,那是测试网络不好的情况.而下面是十个免费的可以用来进行Web的负载/压力测试的工具,这样,你就可以知道你的服务器以及你的W ...
- linux nginx常见问题及优化,压力测试,tomcat服务器优化
nginx常见问题 nginx优化全局配置优化[root@web2 nginx]# vim conf/nginx.confuser nobody;worker_processes 1;(与cpu核心数 ...
- LoadRunner压力测试实例
1 LoadRunner 概要介绍... 2 .项目背景介绍... 5 .使用LoadRunner进行负载/ 实施测试... 16 6.1 Memory相关... 22 6.2 Processor相关 ...
- apache-jmeter-3.3的简单压力测试使用方法
注: 本文参考:http://www.cnblogs.com/TankXiao/p/4045439.html http://blog.csdn.net/lan_shu/article/details/ ...
- 入门级----黑盒测试、白盒测试、手工测试、自动化测试、探索性测试、单元测试、性能测试、数据库性能、压力测试、安全性测试、SQL注入、缓冲区溢出、环境测试
黑盒测试 黑盒测试把产品软件当成是一个黑箱子,只有出口和入口,测试过程中只要知道往黑盒中输入什么东西,知道黑盒会出来什么结果就可以了,不需要了解黑箱子里面是如果做的. 即测试人员不用费神去理解软件里面 ...
- jmeter 压力测试
转自: https://blog.csdn.net/cbzcbzcbzcbz/article/details/78023327 Jmeter压力测试简单教程(包括服务器状态监控) 2017年09月18 ...
- Jmeter压力测试简单教程(包括服务器状态监控)
前段时间公司需要对服务器进行压力测试,包括登录前的页面和登录后的页面,主要目的是测试负载均衡的实现效果.不知道是不是因为Jmeter不如loadRunner火爆还是什么,网上关于Jmeter的资料有很 ...
- JMeter压力测试及服务器状态监控教程
转载自:https://blog.csdn.net/cbzcbzcbzcbz/article/details/78023327 前段时间公司需要对服务器进行压力测试,包括登录前的页面和登录后的页面,主 ...
随机推荐
- js对象2--工厂模式的由来--杂志
一:工厂模式引入前提例子 先看一个案例 <script type="text/javascript"> var person= new Object(); //创建一个 ...
- 飞达资讯App总体介绍及关系架构图
飞达资讯App总体介绍: 下图为飞达资讯App的关系架构图: 该App关系架构图所需的图片云盘链接地址:http://pan.baidu.com/s/1gfHIe4b 提取密码:x1nr 该App的云 ...
- ASPxGridView中批量提交及个别提交的写法
//获取chech box ID protected string GetProtoID() { string protoId = ""; //获取选中的记录Id List< ...
- idea 文件名乱码问题的解决
参考:http://www.cnblogs.com/xingma0910/p/4651889.html idea:文件名乱码:
- Push failed: Failed with error: fatal: Could not read from remote repository.
GitLab push远端,出现错误提示:Push failed: Failed with error: fatal: Could not read from remote repository. 原 ...
- 【缓存】.net中Cache管理操作
隐藏行号 复制代码 ? 这是一段程序代码. using System; using System.Web; using System.Web.Caching; using System.Collect ...
- hbase 新增节点
关于Hbase的集群管理 http://www.linuxidc.com/Linux/2012-07/65909.htm 1.如果只增加集群的存储量,建议增加Hadoop datanode节点. 方法 ...
- Android IOS WebRTC 音视频开发总结(二十)-- 自由职业
咋看标题感觉与WebRTC和音视频无关,其实有着很大的关联,文章来自博客园RTC.Blacker,转载请说明出处. 背景: 一方面因为对开发人员比较了解,不喜欢约束,喜欢自由自在,所以我们向往自由职业 ...
- 完成了server和client的框架设计
界面暂且也不搞.先把框架搭建起来.
- jquery 读取xml
<script type="text/javascript" src="jquery/jquery-1.11.3.min.js"></scri ...