1)下载官方2.64版。
2)安装
./configure make make install. 可执行文件路径为/usr/local/bin/siege.
3)运行查看配置
linux-ntr1:/usr/local/bin # ./siege -C the config file ,filename:/root/.siegerc CURRENT SIEGE CONFIGURATION JoeDog/1.00 [en] (X11; I; Siege 2.56) Edit the resource file to change the settings. ---------------------------------------------- version: 2.56 verbose: true debug: false protocol: HTTP/1.1 connection: close concurrent users: 15 time to run: n/a repetitions: n/a delay: 1 sec internet simulation: false benchmark mode: false failures until abort: 20 named URL: none URLs file: /usr/local/etc/urls.txt logging: true log file: /usr/local/var/siege.log resource file: /root/.siegerc allow redirects: true allow zero byte data: false
可见:版本号,debug模式关闭,并发用户数15,
需要访问的URL列表为/usr/local/etc/urls.txt.
写日志,siege程序的主配置文件为/root/.siegerc.
~~~~~~~~~~~~~~~~~~~~~~~~~~~开始改造
(4)改造1,支持登陆。
由于siege本身是支持登陆的,但是请求头是固定的,而公司的请求头有要求。
改造的原理如下:
load_conf( char *filename ) { ... if( !strncasecmp( option, "login-url", 9 )) { my.login = TRUE; my.loginurl = value; } ... }
所以在配置文件中指定login-url即可:
这里只需要根据配置文件的样板来做即可,POST 后面可以添加JSON格式的数据,比如id啊,密码啊以及其它之类的。 自己处理即可。
之前说了,公司的请求头比较严格,所以需要修改登录URL对应的请求头,也就是添加字段。
如何修改文件头呢?
SIEGEhttp_post { ... else{ rlen=snprintf( request, sizeof( request ), "POST %s %s\015\012" "Host: %s\015\012" "Cookie: %s\015\012" "Accept: */*\015\012" "Accept-Encoding: * \015\012" "User-Agent: %s\015\012%s" "Connection: %s\015\012" "Content-type: application/x-www-form-urlencoded\015\012" "Content-length: %d\015\012\015\012" "%*.*s\015\012", fullpath, protocol, host, cookie, my.uagent, my.extra, keepalive, len, len, (int)len, data ); } }
直接在这里写吗?麻烦。。。为了可配置化。
先扩充数据结构:
struct CONFIG { int logging; /* boolean, log transactions to log file */ int shlog; /* show log file configuration directive. */ char logfile[128]; /* alternative user defined simbot.log */ int verbose; /* boolean, verbose output to screen */ int display; /* boolean, display the thread id verbose */ int config; /* boolean, prints the configuration */ int cusers; /* default concurrent users value. */ int delay; /* range for random time delay, see -d */ int timeout; /* socket connection timeout value, def:10 */ int bench; /* signifies a benchmarking run, no delay */ int internet; /* boolean, tell siege to use random mode. */ int time; /* length of the siege in hrs, mins, secs */ int secs; /* time value for the lenght of the siege */ int reps; /* reps to run the test, default infinite */ char file[128]; /* urls.txt file, default in joepath.h */ int length; /* length of the urls array, made global */ int debug; /* boolean, undocumented debug command */ int mark; /* boolean, signifies a log file mark req. */ char *markstr; /* user defined string value to mark file */ char *url; /* URL for the single hit invocation. */ int protocol; /* 0=HTTP/1.0; 1=HTTP/1.1 */ int cookies; /* boolean, to use cookies or not. */ char uagent[256]; /* user defined User-Agent string. */ char *username; /* WWW-Authenticate user name */ char *password; /* WWW-Authenticate password. */ char *auth; /* WWW-Authenticate base64 usr:pas holder */ int authorize; /* WWW-Authenticate boolean, require auth */ int keepalive; /* boolean, connection keep-alive value */ int signaled; /* timed based testing notification bool. */ char extra[512]; /* extra http request headers */ int proxy; /* boolean, TRUE == use a proxy server. */ char *proxysrv; /* hostname for the proxy server. */ int proxyport; /* port number for proxysrv */ int login; /* boolean, client must login first. */ char *loginurl; /* the initial login URL, first URL hit. */ int failures; /* number of failed attempts before abort. */ int failed; /* total number of socket failures. */ int expire; /* boolean, TRUE == expire cookies ea. run */ int follow; /* boolean, TRUE == follow 302 */ int zero_ok; /* boolean, TRUE == zero bytes data is OK. */ };
在后面加上我们需要的几个字段,为了保密这里就不贴加上的字段了,
然后需要在配置文件中加上key/value.
然后在解析配置文件的函数中添加代码支持:
修改load_conf函数 if(!strncasecmp(option,*key1*, sizeof(*key1*))){ my.key1 = value; } if(!strncasecmp(option,"字段2", sizeof("字段2"))){ my.key2 = value; }
以上代码是示意。
好,现在有了值,我们把字段嵌入到文件头里,
修改SIEGEhttp_post函数即可。
编译查看效果检验正确性。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
测试时报错:
Execution exception[[NullPointerException: null]]
原来是两个问题:
1) http 请求头的content-type /* "Content-type: application/x-www-form-urlencoded\015\012"*/ 修改为 "Content-type: application/json\015\012" 2)配置文件里/root/.siegerc里的login-url的post的内容必须一致为json格式。
再测试,顺利通过!
登陆成功!
~~~~~~~~~~~~~~~~~~~~登陆后,开始执行业务URL
发现取不到之前的cookie.
百般思索,用gdb跟了下,才找到原因,login-url的域名和urls.txt的域名不一致
一个是IP,一个是name.再来修改。
修改完之后还是不行,发现新版增加了cookie超时的功能,怎么破?
问题原因:
函数get_cookie_header内
if(cur->expires <= now) { continue; }
导致之前保存的cookie节点无用。continue直接忽略了。
那么什么时候设置的cur->expires?
~~~~~~~~~~~~~~~~~~~~
http_read_headers函数里,有一个子函数add_cookie( pthread_self(), host, h->cookie );
显然是这里读取请求头,解析请求头,保存cookie
将这里作为突破口!
~~~~
add_cookie函数里有个子函数
parse_cookie(cookiestr, &ck);
看看parse_cookie做了什么事情。
用gdb跟一下,
心得就是:每次都读取cookie的每个字段,跟已经有的cookie字段比较
基本思想就是一个upsert.你懂的。
为了简单,直接在get_cookie_header函数里屏蔽时间比较。
也就是把下面的代码屏蔽
if(cur->expires <= now) { continue; }
然后测试:发现返回
HTTP/1.1 404 Not Found
纳尼?
经过跟测试人员交流,发现测试与生产的代码有差异,生产环境OK,但是测试环境有问题
等待修复!!!Soga。
~~~~~~~~~~~~~~~~~~~~~~~~~~~·waiting...
等待的同时,发现一个问题,配置文件里我指定了2个URL,为啥debug只打出一个url>>>?
本来以为是把代码改错了,看了下代码,才发现原来我为了调试代码设置参数:
并发用户数1 / 每个用户的重复次数为1.
重复次数为1,当然只执行1次URL了。修改为2尝试。
bingo!返回了结果。成功了!
~~~~~~~~~~~~~~~~~~~~~~~~~~~还别高兴太早!
发现了最严重的问题,测试结束后,
Data transferred: 0.00 MB
这又是为啥?
原因就是,如果只是做了几次交互,数量传输比较少,就会造成输出时很小的数字输出0,这是 siege格式控制产生的问题,还得修改最后统计的格式。
屏蔽 fprintf(stderr, "Data transferred:\t%12.2f MB\n", data_get_megabytes(D)); /*%12llu*/ 修改成 fprintf(stderr, "Data transferred:\t%12.2f Bytes\n", data_get_bytes(D)); /*%12llu*/
修改函数
float data_get_throughput(DATA this) { if(this->elapsed==0) return 0; return this->bytes / (this->elapsed * 1024.0*1024.0); }
改造成直接返回this->bytes/ ( this->elapsed ) .
好了,改造完成,开始测试:!!!
这里再设置下超时时间,如果远程服务器返回数据要等很长时间,那就终止连接。
函数
__socket_check
设置了超时时间跟my.timeout有关,默认为:
(gdb) p my.timeout $1 = 30
这个实在等不了,果断修改配置文件。
# Connection timeout value. Set the value in seconds for # socket connection timeouts. The default value is 30 seconds. # ex: timeout = 30 # timeout = 3
大功告成,就是这么简单!