﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-大话人生-随笔分类-性能测试</title><link>http://www.cnitblog.com/stomic/category/7835.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 11 Jun 2014 07:46:39 GMT</lastBuildDate><pubDate>Wed, 11 Jun 2014 07:46:39 GMT</pubDate><ttl>60</ttl><item><title>LoadRunner脚本之EXTRARES参数</title><link>http://www.cnitblog.com/stomic/archive/2014/06/10/89600.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Tue, 10 Jun 2014 12:52:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2014/06/10/89600.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/89600.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2014/06/10/89600.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/89600.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/89600.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: EXTRARES：分隔符，表示标记下一个属性是资源属性的列表（list of resource attributes）。 【EXTRARES后的资源是由script、active、java applet、flash、CSS产生的请求产生的】 and 下面来看看，在EXTRARES后面的资源属性是否可以注释掉...!Let's get the copy and learning started! &...&nbsp;&nbsp;<a href='http://www.cnitblog.com/stomic/archive/2014/06/10/89600.html'>阅读全文</a><img src ="http://www.cnitblog.com/stomic/aggbug/89600.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2014-06-10 20:52 <a href="http://www.cnitblog.com/stomic/archive/2014/06/10/89600.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LoadRunner参数化MD5加密后的参数</title><link>http://www.cnitblog.com/stomic/archive/2013/12/20/89078.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Fri, 20 Dec 2013 10:39:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/12/20/89078.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/89078.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/12/20/89078.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/89078.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/89078.html</trackback:ping><description><![CDATA[<div><table style="word-wrap: break-word; empty-cells: show; border-collapse: collapse; table-layout: fixed; width: 698px; height: 300px; color: #000000; font-family: Tahoma, 'Microsoft Yahei', Simsun; font-size: 14px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 25px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff;" cellpadding="0" cellspacing="0"><tbody style="word-wrap: break-word;"><tr style="word-wrap: break-word;"><td id="article_content" style="word-wrap: break-word; vertical-align: top;"><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">有个项目的请求参数中，有一个参数需要md5加密。在google搜索了些LR调用MD5方法的资料。参考资料实现了参数md5加密。现将方法做下总结：</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">1.首先将md5算法在C编译器中生成md5.h文件，在Vuser generator中添加这个md5.h文件，然后再global.h中添加#include "md5.h"头文件</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">2.调用md5方法：lr_output_message("%s",CMd5("test"))</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">---也可以将md5方法生成dll，然后在LR中调用这个DLL。（此方法没有尝试过）</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">md5方法如下：</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#ifndef MD5_H</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define MD5_H</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#ifdef __alpha</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">typedef unsigned int uint32;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#else</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">typedef unsigned long uint32;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#endif</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">struct MD5Context {</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; uint32 buf[4];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; uint32 bits[2];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; unsigned char in[64];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">};</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">extern void MD5Init();</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">extern void MD5Update();</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">extern void MD5Final();</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">extern void MD5Transform();</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">typedef struct MD5Context MD5_CTX;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#endif</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#ifdef sgi</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define HIGHFIRST</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#endif</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#ifdef sun</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define HIGHFIRST</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#endif</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#ifndef HIGHFIRST</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define byteReverse(buf, len) &nbsp; &nbsp;/* Nothing */</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#else</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">void byteReverse(buf, longs)unsigned char *buf; unsigned longs;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">{</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; uint32 t;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; do {</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; t = (uint32) ((unsigned) buf[3] &lt;&lt; 8 | buf[2]) &lt;&lt; 16 |((unsigned) buf[1] &lt;&lt; 8 | buf[0]);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; *(uint32 *) buf = t;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; buf += 4;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; } while (--longs);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">}</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#endif</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">void MD5Init(ctx)struct MD5Context *ctx;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">{</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ctx-&gt;buf[0] = 0x67452301;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ctx-&gt;buf[1] = 0xefcdab89;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ctx-&gt;buf[2] = 0x98badcfe;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ctx-&gt;buf[3] = 0x10325476;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ctx-&gt;bits[0] = 0;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ctx-&gt;bits[1] = 0;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">}</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">void MD5Update(ctx, buf, len) struct MD5Context *ctx; unsigned char *buf; unsigned len;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">{</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; uint32 t;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; t = ctx-&gt;bits[0];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; if ((ctx-&gt;bits[0] = t + ((uint32) len &lt;&lt; 3)) &lt; t)</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ctx-&gt;bits[1]++;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ctx-&gt;bits[1] += len &gt;&gt; 29;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; t = (t &gt;&gt; 3) &amp; 0x3f;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; if (t) {</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; unsigned char *p = (unsigned char *) ctx-&gt;in + t;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; t = 64 - t;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; if (len &lt; t) {</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; memcpy(p, buf, len);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; return;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; }</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; memcpy(p, buf, t);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; byteReverse(ctx-&gt;in, 16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5Transform(ctx-&gt;buf, (uint32 *) ctx-&gt;in);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; buf += t;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; len -= t;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; }</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; while (len &gt;= 64) {</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; memcpy(ctx-&gt;in, buf, 64);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; byteReverse(ctx-&gt;in, 16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5Transform(ctx-&gt;buf, (uint32 *) ctx-&gt;in);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; buf += 64;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; len -= 64;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; }</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; memcpy(ctx-&gt;in, buf, len);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">}</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">void MD5Final(digest, ctx)</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; unsigned char digest[16]; struct MD5Context *ctx;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">{</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; unsigned count;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; unsigned char *p;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; count = (ctx-&gt;bits[0] &gt;&gt; 3) &amp; 0x3F;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; p = ctx-&gt;in + count;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; *p++ = 0x80;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; count = 64 - 1 - count;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; if (count &lt; 8) {</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; memset(p, 0, count);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; byteReverse(ctx-&gt;in, 16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5Transform(ctx-&gt;buf, (uint32 *) ctx-&gt;in);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; memset(ctx-&gt;in, 0, 56);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; } else {</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; memset(p, 0, count - 8);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; }</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; byteReverse(ctx-&gt;in, 14);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ((uint32 *) ctx-&gt;in)[14] = ctx-&gt;bits[0];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; ((uint32 *) ctx-&gt;in)[15] = ctx-&gt;bits[1];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5Transform(ctx-&gt;buf, (uint32 *) ctx-&gt;in);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; byteReverse((unsigned char *) ctx-&gt;buf, 4);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; memcpy(digest, ctx-&gt;buf, 16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; memset(ctx, 0, sizeof(ctx));</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">}</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define F1(x, y, z) (z ^ (x &amp; (y ^ z)))</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define F2(x, y, z) F1(z, x, y)</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define F3(x, y, z) (x ^ y ^ z)</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define F4(x, y, z) (y ^ (x | ~z))</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">#define MD5STEP(f, w, x, y, z, data, s) ( w += f(x, y, z) + data, &nbsp;w = w&lt;&lt;s | w&gt;&gt;(32-s), &nbsp;w += x )</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">void MD5Transform(buf, in)</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; uint32 buf[4]; uint32 in[16];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">{</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; register uint32 a, b, c, d;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; a = buf[0];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; b = buf[1];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; c = buf[2];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; d = buf[3];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; buf[0] += a;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; buf[1] += b;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; buf[2] += c;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; buf[3] += d;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">}</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">char* CMd5(const char* s)</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">{</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;struct MD5Context md5c;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;unsigned char ss[16];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;char subStr[3],resStr[33];</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;int i;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;MD5Init( &amp;md5c );</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;MD5Update( &amp;md5c, s, strlen(s) );</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;MD5Final( ss, &amp;md5c );</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;strcpy(resStr,"");</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;for( i=0; i&lt;16; i++ )</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;{</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sprintf(subStr, "%02x", ss[i] );</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;itoa(ss[i],subStr,16);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (strlen(subStr)==1) {</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;strcat(resStr,"0");</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;strcat(resStr,subStr);</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;}</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;strcat(resStr,"\0");</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">&nbsp; &nbsp; &nbsp;return resStr;</span></p><p style="word-wrap: break-word; margin: 0px; padding: 0px;"><span style="word-wrap: break-word; line-height: 21.59375px;">}</span></p></td></tr></tbody></table></div><img src ="http://www.cnitblog.com/stomic/aggbug/89078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-12-20 18:39 <a href="http://www.cnitblog.com/stomic/archive/2013/12/20/89078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LoadRunner Error-27791</title><link>http://www.cnitblog.com/stomic/archive/2013/12/13/89010.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Fri, 13 Dec 2013 15:11:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/12/13/89010.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/89010.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/12/13/89010.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/89010.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/89010.html</trackback:ping><description><![CDATA[<div><div> linux下Broken&nbsp;Pipe错误<br />有有可能是linux的线程机制会产生JVM出错的问题，特别是在连接高峰期间经常出现这样的问题，tomcat在linux下也出现类似情况。&nbsp;<br /><br />解决办法是在环境变量中设置：&nbsp;_JAVA_SR_SIGNUM=12&nbsp;基本就可以解决。<br />注意必须是&#8220;_JAVA_SR_SIGNUM=12&#8221;等号两边必须没有空格，等号是半角。。。网上几乎所有答案都是错。。。害人不浅。。。<br />编辑&nbsp;/etc/profile<br />vi&nbsp;&nbsp;&nbsp;/etc/profile<br />在最后一行加上&nbsp;export&nbsp;_JAVA_SR_SIGNUM=12 </div></div><img src ="http://www.cnitblog.com/stomic/aggbug/89010.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-12-13 23:11 <a href="http://www.cnitblog.com/stomic/archive/2013/12/13/89010.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对tomcat下自制应用服务的性能测试小结</title><link>http://www.cnitblog.com/stomic/archive/2013/12/13/89009.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Fri, 13 Dec 2013 14:50:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/12/13/89009.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/89009.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/12/13/89009.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/89009.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/89009.html</trackback:ping><description><![CDATA[&nbsp;<div><p>这次测试的业务流程很简单，是向tomcat下的一个自制应用加压并观测其性能数据。需求也并不复杂尽量多地对服务器加压，多并发多点击。使用的加压机是3台1U服务器，内存分别为32g，32g，16g。测试机是1台1U服务器，内存硬盘cpu都和加压机相仿。不设置集合点，和思考时间，只自定义一个事务。<br />需求对于并发用户数的理想为1000以上，每秒点击在10000以上。开始测试后发现，并发数在100以上后，就开始不断报错，错误主要是以下两种 <wbr></p> <p>Action.c(10): Error -27796: Failed to connect to server "192.168.12.252:81":  [10060] Connection timed out<br />Action.c(10): Error -27791: Server  "192.168.12.252" has shut down the connection prematurely</p> <p>网上查到的解释是，加压机性能过好，导致端口开的过多并且来不及释放造成的，因此修改了加压机的maxport数和tcptimewaitdelay值。重启后测试，问题明显好转但仍然存在。只要并发用户数超过1000，该报错便源源不断，同时随着报错数的不断增加每秒点击数响应降低。初步判断是服务器端来不及响应部分请求导致很多连接超时。调试了很久找到了解决办法，第一步修改runtime  setting下，internet  protocol-preferences-options中几个timeout值，强制使lr发起的http请求的超时变长，要修改的值有http-request  connect timeout，http-request receive timeout，step download  timeout都设置为800秒，顺便提一下，keep-alive http  connections应该是http长短连接的设置，由于本次测试的应用均为短连接，所以该值设为no。修改执行加压，报错和点击数仍然形同水火，一个增加另外一个必然减少。反复查看lr的设置后尝试将tools-options-timeout的各个超时也响应增加。加压后，报错再次得到了显著减少。在1000用户数的情况下点击数可以到达每秒20000次并且报错在万分之1的比例。本以为大功告成，谁知场景运行10分钟后，每秒点击数骤然下降，5分钟之后下降到10000，并且仍有下降趋势。抓耳挠腮一阵后，分析出问题也许出在加大报错timeout后，很多非正常连接尚未断开，在800s后渐渐超时，连接数的减少导致请求数减少。尝试勾选runtime  setting下general-miscellaneous中error handing的设置continue on  error。犹如一弯神器，立竿见影。最终测试结果达到了预期。<br />顺便提一下，analysis下对于响应时间的分析比较具体，不仅可以看到每次迭代的时间，每个事务的时间，还可以具体到请求和返回的网络消耗时间，服务器响应时间等等，具体可以在average  transaction response time图的web page diagnostics中查看，但必须待生成完整日志以后。</p></div><img src ="http://www.cnitblog.com/stomic/aggbug/89009.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-12-13 22:50 <a href="http://www.cnitblog.com/stomic/archive/2013/12/13/89009.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LoadRunner模拟Json请求</title><link>http://www.cnitblog.com/stomic/archive/2013/12/13/89003.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Fri, 13 Dec 2013 07:30:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/12/13/89003.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/89003.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/12/13/89003.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/89003.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/89003.html</trackback:ping><description><![CDATA[<div><div> <div style="line-height: 23.33333396911621px;"> 一、loadrunner脚本创建</div> <div style="line-height: 23.33333396911621px;">1.Insert - New step - 选择 Custom&nbsp;<wbr><span style="line-height: 23.33333396911621px;">Request -&nbsp;<wbr></span><span style="line-height: 23.33333396911621px;">web_custom_request</span></div> <div style="line-height: 23.33333396911621px;"><span style="line-height: 23.33333396911621px;">2.填入相应参数</span></div> <div style="line-height: 23.33333396911621px;"><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=6966650401013z71&amp;url=http://s14.sinaimg.cn/orignal/69666504gc575300c155d" target="_blank"><img src="http://s14.sinaimg.cn/middle/69666504gc575300c155d&amp;690" name="image_operate_39121343012954082" alt="LoadRunner模拟Json请求" title="LoadRunner模拟Json请求" /></a></div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"> 3.生成脚本，并修改如下（参数中的引号"前需要加斜杠\转译）</div> <div style="line-height: 23.33333396911621px;"></div> <div> <div>Action()</div> <div>{</div> <div>&nbsp;<wbr> web_custom_request("web_custom_request",</div> <div>&nbsp;<wbr> "URL=http://urlhead/CpcService.ashx?Method=checkXXXed",</div> <div>&nbsp;<wbr> "Method=POST",</div> <div>&nbsp;<wbr> "Resource=0",</div> <div>&nbsp;<wbr> "RecContentType=application/json",</div> <div>&nbsp;<wbr> "Referer=",</div> <div>&nbsp;<wbr> "Mode=HTTP",</div> <div>&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> "EncType=application/json",</div> <div>&nbsp;<wbr> "Body={\"user\":{\"uid\":\"C8-9C-DC-70-BD-B2\"}}",</div> <div>&nbsp;<wbr> LAST);</div> <div></div> <div>&nbsp;<wbr> return 0;</div> <div>}</div> </div> <div></div> <div>4.<span style="line-height: 23.33333396911621px;">捕获页面返回值</span></div> <div>返回格式{"IsError":0,"ErrorMsg":"","user_tags":["0"]}</div> <div></div> <div> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: 宋体; font-size: 10.5pt;">将光标移动到脚本顶部，插入关联点insert-new&nbsp;<wbr>step-service-web_reg_save_param</span></p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=6966650401013z71&amp;url=http://s1.sinaimg.cn/orignal/69666504g7a256a55fcc0" target="_blank"><img src="http://s1.sinaimg.cn/middle/69666504g7a256a55fcc0&amp;690" name="image_operate_60501343011441700" alt="LoadRunner模拟Json请求" title="LoadRunner模拟Json请求" height="391" width="531" /></a></p> <p style="margin-bottom: 0pt; margin-top: 0pt;"> 在脚本顶部，插入并修改脚本如下<br /></p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> web_reg_save_param("user_tags",</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr>"LB=user_tags\":[\"",</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr>"RB=\"]}",</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr>LAST);</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><br /></p> <p style="margin-bottom: 0pt; margin-top: 0pt;"> 在脚本尾部，加入输出日志验证是否获取成功</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">lr_message ("user_tags:%s", lr_eval_string("{user_tags}"));</p> </div> <div></div> <div>5.对我们的接口做自动化功能测试，写验证脚本如下</div> <div> <div>if (atoi(lr_eval_string("{user_tags}"))==0)&nbsp;<wbr></div> <div>&nbsp;<wbr> &nbsp;<wbr>lr_output_message("user_tags:%s,succeed!",(lr_eval_string("{user_tags}")));</div> <div>else if(atoi(lr_eval_string("{user_tags}"))==1)</div> <div>&nbsp;<wbr> &nbsp;<wbr>lr_output_message("user_tags:%s,failed!",(lr_eval_string("{user_tags}")));</div> <div>else&nbsp;<wbr></div> <div>&nbsp;<wbr> &nbsp;<wbr>lr_output_message("user_tags:%s,unknow!",(lr_eval_string("{user_tags}")));</div> </div> <div></div> <div>6.参数化脚本，</div> <div><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=6966650401013z71&amp;url=http://s9.sinaimg.cn/orignal/69666504gc576a959b148" target="_blank"><img src="http://s9.sinaimg.cn/middle/69666504gc576a959b148&amp;690" name="image_operate_47851343013463561" alt="LoadRunner模拟Json请求" title="LoadRunner模拟Json请求" height="302" width="690" /></a><br /> 运行脚本，重要日志输出如下：</div> <div>Action.c(24): [C8-9C-DC-70-BD-B2]0,succeed!</div> <div>Action.c(26): [C8-9C-DC-70-BD-B3]1,failed!</div> <div></div> <div></div> <div>------------------------------<span style="line-height: 23.33333396911621px;">----</span>-----END<span style="line-height: 23.33333396911621px;">----------------------------</span><span style="line-height: 23.33333396911621px;">----</span><span style="line-height: 23.33333396911621px;">-------</span></div>  </div> <div></div> <div><span style="line-height: 23.33333396911621px;">二、</span><span style="line-height: 23.33333396911621px;">web_custom_request和</span><span style="line-height: 23.33333396911621px;">web_submit_data区别</span></div> <div> <div>web_custom_request方法可以发送POST和GET类型的请求</div> <div>web_submit_data只能发送POST类型的请求</div> <div>所有web_submit_data方法发送的请求都可以使用web_custom_request来实现</div> </div> <div></div> <div> <div>1. web_submit_data</div> <div>请求中提交的数据格式：&#8220;Name=属性名称,&#8221;,&#8220;Value=属性值&#8221;</div> <div>例如&nbsp;<wbr></div> </div> <div>&nbsp;<wbr>&#8220;Name=username&#8221;, &#8220;Value=12044&#8243;, ENDITEM,</div> <div> 如果我们想提交的某个属性包含包含多个值（比如说批量删除），它就无法处理了，只能通过多个web_submit_data来处理。</div> <div>2.&nbsp;<wbr>web_custom_request</div> <div>提交的数据（body）格式：&#8220;Body=属性名称=属性值&amp;属性名称=属性值&amp;&#8230;&#8230;&#8221;</div> <div>例如：</div> <div></div> <div>3.&nbsp;<wbr><span style="line-height: 23.33333396911621px;">web_custom_request 函数详解</span></div> <div> <div><span style="line-height: 23.33333396911621px;">A.语法：</span></div> <div>Int web_custom_request (const char *RequestName,&nbsp;<wbr></div> <div>&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &lt;List of Attributes&gt;,</div> <div>&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> [EXTRARES,&nbsp;<wbr><span style="line-height: 23.33333396911621px;">&lt;List of Resource Attributes&gt;,]&nbsp;<wbr></span></div> <div><span style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> LAST );</span></div> <div><span style="line-height: 23.33333396911621px;"><br /></span></div> </div> <div>B.返回值：返回LR_PASS（0）代表成功，LR_FAIL（1）代表失败。</div> <div></div> <div>C.参数：</div> <div>(1)<strong>RequestName</strong>：步骤的名称，VuGen中树形视图中显示的名称。</div> <div>(2)List of Attribute：属性列表，支持的属性有以下几种：</div> <div>a.<strong>URL</strong>：页面地址。</div> <div>b.<strong>Method</strong>&nbsp;<wbr>：页面的提交方式，POST或GET。</div> <div>c.<strong>TargetFrame</strong>：当前链接或资源所在Frame的名称。</div> <div>除了Frame的名字，还可以指定下面的参数：</div> <div>&nbsp;<wbr> &nbsp;<wbr> _BLANK：打开一个空窗口。</div> <div>&nbsp;<wbr> &nbsp;<wbr> _PARENT：把最新更改过的的Frame替换为它的上级。</div> <div>&nbsp;<wbr> &nbsp;<wbr> _SELF：替换最新更改过的的Frame。</div> <div>&nbsp;<wbr> &nbsp;<wbr> _TOP：替换整个页面。</div> <div></div> <div>d.EncType：编码类型。</div> <div></div> <div>e.<strong>RecContentType</strong>：<span style="line-height: 23.33333396911621px;">录制脚本时响应头的内容类型。</span></div> <div>例如text/html,application/x-javascript,application/json等。</div> <div>当没有设置Resource属性时，用它来确定目标URL是否是可记录的资源。此属性包含主要的和次要的资源。</div> <div>最频繁使用的类型是 text、application、image。次要的类型根据资源不同变化很多。例如："RecContentType=text/html"：表示 html文本。"RecContentType=application/msword"：表示当前使用的是Msword。</div> <div></div> <div>f.<span style="line-height: 23.33333396911621px;"><strong>Resource</strong>：指示URL是否属于资源。1 是；0 不是。</span><span style="line-height: 23.33333396911621px;">设置了这个参数后，RecContentType参数被忽略。</span></div> <div><span style="line-height: 23.33333396911621px;">&#8220;Resource=1&#8221;，意味着当前操作与所在脚本的成功与否关系不大。在下载资源时如果发生错误，是当作警告而不是错误来处理的；URL是否被下载受&#8220;Run-Time Setting&#8212;Browser Emulation--Download non-HTML resources&#8221; 这个选项的影响。此操作的响应信息是不做为HTML来解析的。</span></div> <div><span style="line-height: 23.33333396911621px;">&#8220;Resource=0&#8221;，表明此URL是重要的，不受发送请求（RTS）的影响，在需要时也会解析它。</span></div> <div><span style="line-height: 23.33333396911621px;"><br /></span></div> g.ResourceByteLimit：web页面下载资源的极限大小。当达到设置的极限后，无法下载其他资源。仅仅对需要下载的资源有效。  <div style="line-height: 23.33333396911621px;"> 下载过程：如果总计下载大小小于极限值，则正常开始下载。如果当下载时达到了设置的极限值，资源大小可知（在HTTP响应头中指定了Content- Length），这中情况下，如果只需要一个缓冲区，那么下载可以正常完成。如果需要的不止一个缓冲区，或者资源大小不可知，下载就会中断同时关闭当前连 接。</div> <div style="line-height: 23.33333396911621px;"> 这个特性可以用来模拟用户不等待一个页面下载完成时导航到另一个页面的情况。</div> <div style="line-height: 23.33333396911621px;">ResourceByteLimit 在HTTP模式中无法使用，在Concurrent Groups（Vuser脚本中的一个区，此区中的所有函数并发执行）区中也无法使用。仅仅适用于Sockets的回放，WinInet也是不适用的</div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"> <div>h.Snapshot：快照的文件名，关联时使用。</div> <div>i.<strong>Mode</strong>：两种录制级别HTML、HTTP。</div> </div> <div style="line-height: 23.33333396911621px;"> <div> HTML级别：在当前Web界面上录制直观的HTML动作。以一步步的web_url、web_link、web_image、web_submit_form来录制这些动作。VuGen仅仅录制返回HTML页面的请求，不处理脚本和应用程序。</div> <div></div> <div> HTTP级别：VuGen把所有的请求录制为web_url指令，不生成web_link、web_image、web_submit_form这些函数。这种方法更为灵活，但是生成的脚本不够直观。</div> </div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"> j.<strong>Body</strong>：请求体。（目前仅适用与web_custom_request函数）</div> <div style="line-height: 23.33333396911621px;"> 不同的应用中，请求体分别通过Body、BodyBinary或者BodyUnicode参数来传递。请求体可以只使用其中一个参数，也可以使用一连串的分开的参数组成多请求体。</div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;">k.RAW BODY：参见List of Attributes的同名参数。</div> <div style="line-height: 23.33333396911621px;">l. BodyFilePath：作为请求体传送的文件的路径。它不能与下面的属性一起使用：Body，或者其他Body属性或Raw Body属性包括BodyBinary，BodyUnicode， RAW_BODY_START或Binary=1。</div> <div style="line-height: 23.33333396911621px;"><span style="line-height: 23.33333396911621px;">m.Binary：</span></div> <div style="line-height: 23.33333396911621px;"> <div style="line-height: 23.33333396911621px;"> &#8220;Binary=1&#8221;表示页面请求体中的每一个以file://x/##形式出现的值（在这里&#8220;##&#8221;代表2个十六进制数字），都会被替换为单字节的十六进制的值。</div> <div style="line-height: 23.33333396911621px;"> 如果&#8220;Binary=0&#8221;（默认值），所有的字符序列只是按照字面的值传递。</div> <div style="line-height: 23.33333396911621px;"> 需要注意双斜杠的用法。在C编译器中双斜杠被解释为单斜杠。如果不需要零字节，单斜杠可以在Binary不等于1的情况下使用（例如，使用\x20代替file://x20/）。如果需要零字节，那么只能使用file://x00/且设置 &#8220;Binary=1&#8221;，\x00在逻辑上会被截断。</div> </div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"> n.ContentEncoding</div> <div style="line-height: 23.33333396911621px;"> 指定请求体的使用指定的方式（gzip或者deflate）进行编码（例如，压缩），相应的&#8220;Content-Encoding:&#8221; HTTP头会和此请求一起发送。这个参数适用于web_custom_request和web_submit_data。</div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"><span style="line-height: 23.33333396911621px;">o.Referer：当前页面关联的页面。如果已经显式指定了url的地址，此项可以省略。</span></div> <div style="line-height: 23.33333396911621px;"><span style="line-height: 23.33333396911621px;"><br /></span></div> <div style="line-height: 23.33333396911621px;"> <div style="line-height: 23.33333396911621px;"> p.ExtraResBaseDir：</div> <div> <div> （目前仅适用与web_custom_request函数）：根URL，放在EXTRARES组里。它是用来解析相对URL的（译者加：类似于Windows的相对路径和绝对路径）。</div> <div> URL可以是绝对路径（例如http://weather.abc.com/weather/forecast.jsp?locCode=LFPO），也可以是相对路径（例如&#8220;forecast.jsp?locCode=LFPO&#8221;）。</div> <div> 真正的URL的下载是通过绝对路径进行的，所以相对URL路径必须使用根路径URL去解析。例如，使用http://weather.abc.com /weather/做为根路径来解析&#8220;forecast.jsp?locCode=LFPO&#8221;，最后的URL是：http: //weather.abc.com/weather/forecast.jsp?locCode=LFPO。如果没有指定 &#8220;ExtraResBaseDir&#8221;，默认的根URL是主页面的URL。</div> </div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"> q.UserAgent：用户代理，它是一个HTTP头的名字，用来标识应用程序，通常是浏览器，它呈现的是用户和服务器的交互。</div> </div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"> <div style="line-height: 23.33333396911621px;"> (3)EXTRARES：表明下面的参数将会是List Of Resource Attributes了。&nbsp;<wbr></div> <div style="line-height: 23.33333396911621px;">(4)LAST ：结尾的标示符。</div></div> <div style="line-height: 23.33333396911621px;"><span style="line-height: 23.33333396911621px;">-------------------------------------------------------------</span></div> <div style="line-height: 23.33333396911621px;">附：测试页面</div> <div style="line-height: 23.33333396911621px;"> &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;</div> <div style="line-height: 23.33333396911621px;">&lt;html xmlns="http://www.w3.org/1999/xhtml" &gt;</div> <div style="line-height: 23.33333396911621px;"> &lt;head&gt;</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &lt;title&gt;&lt;/title&gt;</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &lt;script src="http://img.m18.com/web/j/lib/jquery-1.3.2.min.js" type="text/javascript"&gt;&lt;/script&gt;</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &lt;script type="text/javascript"&gt;</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> $(function() {</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr>$.ajax({</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr>type: "POST",</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr>contentType: "application/json",</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> url: "http://url.com/mkt/CpcService.ashx?Method=checkhasactivated",</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> data: '{"user":{"uid":"C8-9C-DC-70-BD-B2"}}',</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> success: function(msg) {</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> alert("Data Saved: " + msg);</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> }</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr>});</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> })</div> <div style="line-height: 23.33333396911621px;">&nbsp;<wbr> &nbsp;<wbr> &lt;/script&gt;</div> <div style="line-height: 23.33333396911621px;"> &lt;/head&gt;</div> <div style="line-height: 23.33333396911621px;"> &lt;body&gt;</div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"> &lt;/body&gt;</div> <div style="line-height: 23.33333396911621px;"> &lt;/html&gt;</div> <div style="line-height: 23.33333396911621px;"> -----------------------------------------------------------</div> <div style="line-height: 23.33333396911621px;"> <div>web_reg_save_param("user_tags",</div> <div>"LB=user_tags\":[\"",</div> <div>"RB=\"]}",</div> <div>LAST);</div> <div></div> <div>web_custom_request("web_custom_request",</div> <div>"URL=http://XXX/CpcService.ashx?Method=checkXXXed",</div> <div>"Method=POST",</div> <div>"Resource=1",</div> <div>"RecContentType=application/json",</div> <div>"Referer=",</div> <div>"Mode=HTTP",</div> <div>&nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> "EncType=application/json",</div> <div>"Body={\"user\":{\"uid\":\"{mac}\"}}",</div> <div>LAST);</div> <div>&nbsp;<wbr> &nbsp;<wbr> //lr_message ("user_tags:%s", lr_eval_string("{user_tags}"));</div> <div>&nbsp;<wbr> &nbsp;<wbr> if (atoi(lr_eval_string("{user_tags}"))==0)&nbsp;<wbr></div> <div> lr_output_message("[%s]%s,succeed!",(lr_eval_string("{mac}")),(lr_eval_string("{user_tags}")));</div> <div>else if(atoi(lr_eval_string("{user_tags}"))==1)</div> <div> lr_output_message("[%s]%s,failed!",(lr_eval_string("{mac}")),(lr_eval_string("{user_tags}")));</div> <div>else&nbsp;<wbr></div> <div> lr_output_message("[%s]%s,unknow!",(lr_eval_string("{mac}")),(lr_eval_string("{user_tags}")));</div> </div> <div style="line-height: 23.33333396911621px;"> -----------------------------------------------------------</div> <div style="line-height: 23.33333396911621px;"></div> <div style="line-height: 23.33333396911621px;"><a href="http://blog.csdn.net/yong_sun/article/details/6733096">http://blog.csdn.net/yong_sun/article/details/6733096</a></div></div><img src ="http://www.cnitblog.com/stomic/aggbug/89003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-12-13 15:30 <a href="http://www.cnitblog.com/stomic/archive/2013/12/13/89003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Error -26601: Decompression function 错误解决 </title><link>http://www.cnitblog.com/stomic/archive/2013/12/07/88927.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Sat, 07 Dec 2013 12:58:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/12/07/88927.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/88927.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/12/07/88927.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/88927.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/88927.html</trackback:ping><description><![CDATA[<div><div id="article_content">  <p style="color:#333333; font-family:Arial; font-size:14px; line-height:26px"> Action2.c(30): Error -26601: Decompression function  (wgzMemDecompressBuffer) failed, return code=-5 (Z_BUF_ERROR), inSize=0,  inUse=0, outUse=0<br /> 这个错误为数据包较大，未下载完整或其他原因导致解压错误。</p> <p style="color:#333333; font-family:Arial; font-size:14px; line-height:26px"> 解决方法：增加network&nbsp; buffer size,默认值为12288。</p> <p style="color:#333333; font-family:Arial; font-size:14px; line-height:26px"> 操作步骤：1.进入运行时设置&nbsp;；</p> <p style="color:#333333; font-family:Arial; font-size:14px; line-height:26px"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;2.internet protocol-&gt;preferences-&gt;options-&gt;general-&gt;network buffer size</p>  </div></div><img src ="http://www.cnitblog.com/stomic/aggbug/88927.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-12-07 20:58 <a href="http://www.cnitblog.com/stomic/archive/2013/12/07/88927.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LR学习笔记---参数设置</title><link>http://www.cnitblog.com/stomic/archive/2013/11/28/88848.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Thu, 28 Nov 2013 11:54:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/11/28/88848.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/88848.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/11/28/88848.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/88848.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/88848.html</trackback:ping><description><![CDATA[<div><p>LR在录制程序运行的过程中，VuGen（脚本生成器） 自动生成了包含录制过程中实际用到的数值的脚本，如果你企图在录制的脚本中使用不同的数值执行脚本的活动（如查询、提交等等），那么你必须用参数值取代录制的数值，这个过程叫做参数化。</p> <p>以下为参数化过程：</p> <div><img style="margin: 0px 10px 0px 0px; width: 561px; height: 290px;" alt="LR学习笔记---参数设置 - 毛毛虫 - 想飞的梦想" src="http://img762.ph.126.net/sRvMmjbT-eO1OiBJYYyB_A==/4888094445557394118.jpg" height="348" width="595" /></div> <div>&nbsp;</div> <div>参数化过程比较简单，参数化时复杂的是对参数属性的设置。主要是以下两个属性的组合。</div> <div>select&nbsp; next row 中有三个选项：&nbsp; Sequential（顺序读取）、Random（随机读取）、Unique （唯一）</div> <div>update the value 中也有三个选项：&nbsp; Each Occurrence（每次遇到&nbsp;）、&nbsp; Each iteration（每次迭代&nbsp;&nbsp;）、 Once（一直&nbsp;）</div> <div>这两个属性可以有九种组合方式，每种方式都不一样。接下来我们就用一个小实例来验证一下每种取值方式的效果。</div> <div>录制一个lr自带实例WebTours的定单脚本。脚本中将出发城市与到达城市均参数化一下。参数化后还需做个关联（这个就重点说了）保证回放脚本成功。</div> <div>设置10个用户并发持续加载的场景（参数文件中有10个数据），用默认设置均可。即每15秒加载两个用户，持续时间为5分钟，每30秒停止5个用户。</div> <div>然后并发跑脚本。</div> <div>以下为9种组合的测试结果：</div> <div>（1）sequential&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Once</div> <div>十个用户 每个用户取值均一样，，每个用户的所有迭代中的取值均一样。</div> <div>第一个用户执行了5次迭代，每次迭代均取得第一个参数。</div> <div>第二个用户也执行了5次迭代，每次迭代均取的第一个参数。</div> <div>第三个。。第四个。等等十个用户均一样。</div> <div>&nbsp;（2）unique&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; once</div> <div>&nbsp; 十个用户 每个用户取值都唯一，每个用户的所有迭代中的取值均一样。</div> <div>&nbsp;第一个用户执行了5次迭代，每次迭代均取第一个参数；</div> <div>&nbsp;第二个用户执行了5次迭代，每次迭代均取第二个参数；</div> <div>&nbsp;第三个。。。第四个。。。依此类推。</div> <div>&nbsp;第十个用户执行了5次迭代，每次迭代均取第十个参数。</div> <div>（3）Random&nbsp; Once</div> <div>十个用户，每个用户为随机取值，每个用户的所有迭代中的取值均一样。</div> <div>第一个用户执行了5次迭代，每次迭代均取第三个参数； <br />第二个用户执行了5次迭代，每次迭代均取第七个参数；<br />第三个。。。第四个。。。依此类推十个用户随机取值。</div> <div>（4）Sequential&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Each&nbsp;iteration</div> <div>&nbsp;十个用户，每个用户每次迭代取一个新值。</div> <div>第一个用户，第一迭代，取第一个参数&nbsp;；第二次迭代，取第二个参数 。。。。第十次迭代，取第十个参数。</div> <div>第二个用户，第一次迭代，取第一个参数；第二次迭代，取第二个参数 。。。。第十次迭代，取第十个参数。</div> <div>第三个。。第四个。。。依此类推。</div> <div>（5）Unique&nbsp;&nbsp;&nbsp;&nbsp; Each iteration</div> <div>由于只设置了十个参数，运行过程中报参数不足的错误。</div> <div>第一个用户，第一次迭代，取第一个参数；第二次迭代报错。。。第十次迭代报错。</div> <div>第二个用户，第一次迭代，取第二个参数；第二次迭代报错。。。第十次迭代报错。</div> <div>第三个。。第四个。。依此类推。</div> <div>&nbsp;</div> <div>如果修改为100个参数则：</div> <div>第一个用户，第一迭代，取第一个参数&nbsp;；第二次迭代，取第二个参数 。。。。第十次迭代，取第十个参数。<br />第二个用户，第一次迭代，取第十一个参数；第二次迭代，取第十二个参数 。。。。第十次迭代，取第二十个参数。<br />第三个。。第四个。。。依此类推。</div> <div>（6）Random&nbsp;&nbsp;&nbsp;&nbsp; Each Iteration</div> <div>十个用户，每个用户每次迭代均随机去一个值。</div> <div>第一个用户，第一迭代，取第一个参数&nbsp;；第二次迭代，取第四个参数 。。。。第十次迭代，取第七个参数。<br />第二个用户，第一次迭代，取第三个参数；第二次迭代，取第二个参数 。。。。第十次迭代，取第一个参数。<br />第三个。。第四个。。。依此类推。</div> <div>（7）Sequential&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Each ocurrance</div> <div>十个用户，每个用户每次遇到均取一个值。</div> <div>第一个用户，第一次迭代，每次遇到顺序取一个值；第二次迭代，按顺序接着取值。。。。。</div> <div>第二个用户，第一次迭代，每次遇到顺序取一个值（从第一个参数开始）；第二次迭代，按顺序接着取值。。。。。</div> <div>依此类推。</div> <div>（8） unique&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Each occurrance</div> <div>&nbsp;十个用户，每个用户每次遇到均取一个不同的值。</div> <div>&nbsp;参数列表中要有足够的参数。</div> <div>&nbsp;</div> <div>（9） Random&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Each Occurrance</div> <div>十个用户，每个用户每次遇到随机取一个值。</div> <div>第一个用户，第一次迭代，每次遇到随机取一个值，第二次迭代，随机再取值。。。。。</div> <div>第二个用户，第一次迭代，每次遇到随机取一个值，第二次迭代，随机再取值。。。。。</div> <div>依此类推。</div> <div>&nbsp;</div> <div>总之，主要区分 sequential 、Unique、Random 的区别。</div> <div>sequential为顺序取，每个用户均从第一个参数开始取值。</div> <div>Unique为唯一，每个用户取值均不同。</div> <div>Random 为随机，每个用户均随机取值。</div></div><img src ="http://www.cnitblog.com/stomic/aggbug/88848.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-11-28 19:54 <a href="http://www.cnitblog.com/stomic/archive/2013/11/28/88848.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LR 手动关联</title><link>http://www.cnitblog.com/stomic/archive/2013/11/25/88836.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Mon, 25 Nov 2013 05:09:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/11/25/88836.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/88836.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/11/25/88836.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/88836.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/88836.html</trackback:ping><description><![CDATA[<div id="xspace-showmessage" class="xspace-itemmessage"><a href="javascript.:;" target="_self"><u><strong><font color="#000066">手动关联</font></strong></u></a>的过程大致如下： 
<p>　　第一步：录制<a href="javascript.:;" target="_self"><u><strong></strong></u></a><u><strong><a target="_self"><u><strong><font color="#000066">测试</font></strong></u></a></strong></u>脚本，录制二遍</p>
<p>　　第二步：使用WinDiff工具找出两次脚本的不同，判断是否需要进行关联</p>
<p>　　第三步：确定插入关联的位置</p>
<p>　　第四步：在VIEW TREE中使用web_reg_save_param函数手动建立关联</p>
<p>　　第五步：将脚本中有用到关联的数据，用参数代替</p>
<p>　　第六步：验证关联的正确性</p>
<p>　　<strong>下面详细介绍：</strong></p>
<p>　　<strong>第一步：录制测试脚本，录制二遍</strong></p>
<p>　　这一步就不用多说了，相同的操作，录制两份，分别保存</p>
<p>　　<strong>第二步：使用WinDiff工具协助找出需要关联的数据</strong></p>
<p>　　1. 在第二份脚本中，点选VuGen的【Tools】&gt;【Compare with Vuser&#8230;】，并选择第一份脚本。</p>
<p>　　2. 接着WinDiff会开启，同时显示二份脚本，并显示有差异的地方。WinDiff会以一整行黄色标示有差异的脚本，并且以红色的字体显示真正差异的文字。（假如没看到红色字体，请点选【Options】&gt;【View】&gt;【Show Inline Differences】）。</p>
<p>　　查看二份脚本中差异的部份，每一个差异都可能是需要做关联的地方。</p>
<p>　　注意：lr_thik_time部分的差异可以忽略</p>
<p>　　找到不同的部分后，复制，然后打开Recording Log或是Generation Log，按Ctrl+F，在查找窗口中粘贴差异部分的内容，点击查找找到后，查看该部分的信息，确认是客户端的请求信息还是服务器回应的信息</p>
<p>　　如果出现在$$$$$$ Request Header For Transaction With Id 3 Ended $$$$$$这个部分，那证明是客户端发出的请求，这里是不需要做关联的</p>
<p>　　一般做的关联都是出现在****** Response Header For Transaction With Id 7 ******和****** Response Body For Transaction With Id 7 ******中的部分。</p>
<p>　　在找到这个信息后，需要记录如下信息：</p>
<p>　　a、记录这个不同数据之前的内容和之后的内容</p>
<p>　　b、记录这个不同数据出现的位置，是Header还是Body</p>
<p>如：</p>
<p class="pExample">&lt;tr bgcolor=#66cccc&gt;&lt;th&gt;Flight&lt;th&gt;Departure time&lt;th&gt;Cost </p><a name="wp49876"></a>
<p class="pExample">&lt;tr bgcolor=#66CCff&gt;&lt;td align=center&gt;&lt;input type = radio name=<strong style="font-weight: bold">outboundFlight value=230;378;11/20/2003 checked &gt;</strong>Blue Sky Air 230&lt;td align=center&gt;8am&lt;td align=center&gt;$ 378 </p><a name="wp49877"></a>
<p class="pExample"><br /></p>
<p><strong>　第三步：确认插入关联的位置</strong></p>
<p>　　我们在<a target="_self"><u><strong><font color="#000066">日志</font></strong></u></a>中找到了两次脚本的不同点的位置，根据这个位置，我们再确定是在哪个请求之后产生的，也就是说要定位发生不同点的response是由哪个request产生的，找到了这个请求的函数位置，我们就知道要往哪里做关联了。</p>
<p>　　一般情况下关联函数写到发出请求的函数之前就可以了。</p>
<p>　　<strong>第四步：插入关联函数</strong></p>
<p>　　在插入关联函数前，我们先介绍关联函数web_reg_save_param</p>
<p>　　一个web_reg_save_param函数的例子：</p>
<table style="border-bottom: rgb(153,153,153) 1px solid; border-left: rgb(153,153,153) 1px solid; background-color: rgb(221,221,221); width: 360px; height: 25px; font-size: 12px; border-top: rgb(153,153,153) 1px solid; border-right: rgb(153,153,153) 1px solid" align="center">
<tbody>
<tr>
<td>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;<strong style="font-weight: bold">web_reg_save_param</strong>("outFlightVal", </p><a name="wp50007"></a>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;"LB=outboundFlight value=", <br /></p>
<p class="pExample">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "RB= checked &gt;",</p>
<p class="pExample">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LAST); </p></td></tr></tbody></table>
<p>　由此可以看出，作边界LB与右边界RB直接的值为要关联的值。</p>
<p>在此例，即&#8220;<strong style="font-weight: bold">230;378;11/20/2003&#8221;</strong></p>
<p>在这里我们只介绍几个常用参数的含义</p>
<p>　　语法：int web_reg_save_param(const char *ParamName, &lt;list of Attributes&gt;, LAST);</p>
<p>　　参数说明:</p>
<p>　　ParamName: 存放得到的动态内容的参数名称</p>
<p>　　list of Attributes: <a target="_self"><u><strong><font color="#000066">其它</font></strong></u></a>属性，包括：Notfound, LB, RB, RelFrameID, Search, ORD, SaveOffset, Convert, SaveLen。属性值不分大小写</p>
<p>　　LB( Left Boundary ) : 返回信息的左边界字串。该属性必须有，并且区分大小写。</p>
<p>　　RB( Right Boundary ): 返回信息的右边界字串。该属性必须有，并且区分大小写。</p>
<p>　　Search : 返回信息的查找范围。可以是Headers，Body，Noresource，All(缺省)。该属性质可有可无。</p>
<p>　　那么如何插入该关联函数呢？</p>
<p>　　1.将vugun切换到 view tree 模式下</p>
<p>　　2.在左边的列表中，找到在上一步发出请求的函数，点击&#8220;右键&#8221;</p>
<p>　　选择&#8220;insert before&#8221;</p>
<p>　　3.在弹出的&#8220;add step&#8221;对话框的&#8220;find function&#8221;中输入&#8220;web_reg_save_param&#8221;，点击&#8220;ok&#8221;</p>
<p>　　在&#8220;parameter name&#8221;中输入,关联函数的名称，这里最好有含义，&#8220;sessionid&#8221;</p>
<p>　　在&#8220;left boundary&#8221;中输入，刚才记录下的不同点字符串的左面的几个字符，定义左边界</p>
<p>　　在&#8220;right boundary&#8221;中输入，刚才记录下的不同点字符串的右面的几个字符，定义右边界，;</p>
<p>　　在&#8220;search in &#8221;中，选择&#8220;body&#8221;</p>
<p>　　点击&#8220;ok&#8221;</p>
<p>　　4.回到脚本编辑模式下，查看该函数插入是否正确</p>
<p>　　在发出请求的函数前应该看到：</p>
<table style="border-bottom: rgb(153,153,153) 1px solid; border-left: rgb(153,153,153) 1px solid; background-color: rgb(221,221,221); width: 80%; font-size: 12px; border-top: rgb(153,153,153) 1px solid; border-right: rgb(153,153,153) 1px solid" align="center">
<tbody>
<tr>
<td>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;<strong style="font-weight: bold">web_reg_save_param</strong>("outFlightVal", </p><a name="wp50007"></a>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;"LB=outboundFlight value=", <br /></p>
<p class="pExample">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "RB= checked &gt;",</p>
<p>　　"Search=Body",</p>
<p>　　LAST);</p></td></tr></tbody></table>
<p>　　<strong>第五步：将脚本中有用到关联的数据，用参数代替</strong></p>
<p>　　如发出请求的参数如下，那么将原来服务器返回的动态值使用{ outFlightVal} 来替换：</p>
<table style="border-bottom: rgb(153,153,153) 1px solid; border-left: rgb(153,153,153) 1px solid; background-color: rgb(221,221,221); width: 360px; height: 274px; font-size: 12px; border-top: rgb(153,153,153) 1px solid; border-right: rgb(153,153,153) 1px solid" align="center">
<tbody>
<tr>
<td>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;web_submit_form("reservations.pl_2", </p><a name="wp49992"></a>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;"Snapshot=t5.inf", </p><a name="wp49993"></a>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ITEMDATA, </p><a name="wp49994"></a>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;"Name=outboundFlight", "Value={<strong style="font-weight: bold">outFlightVal</strong>}", ENDITEM, </p><a name="wp49995"></a>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;"Name=reserveFlights.x", "Value=92", ENDITEM, </p><a name="wp49996"></a>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;"Name=reserveFlights.y", "Value=10", ENDITEM, </p><a name="wp49997"></a>
<p class="pExample">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;LAST); </p></td></tr></tbody></table>
<p>　　<strong>第六步：验证关联的正确性</strong></p>
<p>　　回放脚本，验证关联的正确性。</p>
<p>　　OK！！！</p>
<p>　　大功告成。</p></div><img src ="http://www.cnitblog.com/stomic/aggbug/88836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-11-25 13:09 <a href="http://www.cnitblog.com/stomic/archive/2013/11/25/88836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Loadrunner测试实例分析</title><link>http://www.cnitblog.com/stomic/archive/2013/11/19/88829.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Tue, 19 Nov 2013 07:06:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/11/19/88829.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/88829.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/11/19/88829.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/88829.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/88829.html</trackback:ping><description><![CDATA[<div><p>　LoadRunner性能测试结果分析是个复杂的过程，通常可以从结果摘要、并发数、平均事务响应时间、每秒点击数、业务成功率、系统资源、网页细分图、Web服务器资源、数据库服务器资源等几个方面分析，如图1- 1所示。<span style="color: #0000ff;">性能测试结果分析的一个重要的原则是以性能测试的需求指标为导向。</span>我们回顾一下本次性能测试的目的，正如 所列的指标，本次测试的要求是验证在30分钟内完成2000次用户登录系统，然后进行考勤业务，最后退出，在业务操作过程中页面的响应时间不超过3秒，并且服务器的CPU使用率、内存使用率分别不超过75%、70%，那么按照所示的流程，我们开始分析，看看本次测试是否达到了预期的性能指标，其中又有哪些性能隐患，该如何解决。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111614584562.jpg" /></p><p> </p><p>图1- 1性能测试结果分析流程图</p><ul style="list-style-type: square;"><li>结果摘要</li></ul><p>　　　LoadRunner进行场景测试结果收集后，首先显示的该结果的一个摘要信息，如图1- 2所示。概要中列出了场景执行情况、&#8220;Statistics Summary（统计信息摘要）&#8221;、&#8220;Transaction Summary（事务摘要）&#8221;以及&#8220;HTTP Responses Summary（HTTP响应摘要）&#8221;等。以简要的信息列出本次测试结果。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615003274.jpg" /></p><p> </p><p>图1- 2性能测试结果摘要图</p><p><strong>场景执行情况</strong></p><p>该部分给出了本次测试场景的名称、结果存放路径及场景的持续时间，如图5- 3所示。从该图我们知道，本次测试从15:58:40开始，到16:29:42结束，共历时31分2秒。与我们场景执行计划中设计的时间基本吻合。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615015414.jpg" /></p><p> 图1- 3场景执行情况描述图</p><p><strong>Statistics Summary</strong><strong>（统计信息摘要）</strong></p><p>该部分给出了场景执行结束后并发数、总吞吐量、平均每秒吞吐量、总请求数、平均每秒请求数的统计值，如图5- 4所示。从该图我们得知，本次测试运行的最大并发数为7，总吞吐量为842,037,409字节，平均每秒的吞吐量为451,979字节，总的请求数为211,974，平均每秒的请求为113.781，<span style="color: #0000ff;">对于吞吐量，单位时间内吞吐量越大，说明服务器的处理能越好，而请求数仅表示客户端向服务器发出的请求数，与吞吐量一般是成正比关系。</span></p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615032034.jpg" /></p><p>图1- 4统计信息摘要图</p><p><strong>Transaction Summary</strong><strong>（事务摘要）</strong></p><p>该部分给出了场景执行结束后相关Action的平均响应时间、通过率等情况，如图1- 5所示。从该图我们得到每个Action的平均响应时间与业务成功率。</p><p>注意：</p><div><p>　　因为在场景的&#8220;Run-time Settings&#8221;的&#8220;Miscellaneous&#8221;选项中将每一个Action当成了一个事务执行，故这里的事务其实就是脚本中的Action。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615060347.jpg" /></p></div><p> 图1- 5事务摘要图</p><p><strong>HTTP Responses Summary</strong><strong>（HTTP</strong><strong>响应摘要）</strong></p><p>该部分显示在场景执行过程中，每次HTTP请求发出去的状态，是成功还是失败，都在这里体现，如图5- 6所示。从图中可以看到，在本次测试过程中LoadRunner共模拟发出了211974次请求（与&#8220;统计信息摘要&#8221;中的&#8220;Total Hits&#8221;一致），其中&#8220;HTTP 200&#8221;的是209811次，而&#8220;HTTP 404&#8221;则有2163，说明在本次过程中，经过发出的请求大部分都能正确响应了，但还是有部分失败了，但未影响测试结果，&#8220;HTTP 200&#8221;表示请求被正确响应，而&#8220;HTTP 404&#8221;表示文件或者目录未能找到。<span style="color: #0000ff;">有朋友可能会问，这里出现了404的错误，为什么结果还都通过了。出现这样问题的原因是脚本有些页面的请求内容并非关键点，比如可能请求先前的cookie信息，如果没有就重新获取，所以不会影响最终的测试结果。</span></p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615082087.jpg" /></p><p>图1- 6 HTTP响应摘要</p><p>常用的HTTP状态代码如下：</p><div><p>400 无法解析此请求。</p><p>401.1 未经授权：访问由于凭据无效被拒绝。</p><p>401.2 未经授权: 访问由于服务器配置倾向使用替代身份验证方法而被拒绝。</p><p>401.3 未经授权：访问由于 ACL 对所请求资源的设置被拒绝。</p><p>401.4 未经授权：Web 服务器上安装的筛选器授权失败。</p><p>401.5 未经授权：ISAPI/CGI 应用程序授权失败。</p><p>401.7 未经授权：由于 Web 服务器上的 URL 授权策略而拒绝访问。</p><p>403 禁止访问：访问被拒绝。</p><p>403.1 禁止访问：执行访问被拒绝。</p><p>403.2 禁止访问：读取访问被拒绝。</p><p>403.3 禁止访问：写入访问被拒绝。</p><p>403.4 禁止访问：需要使用 SSL 查看该资源。</p><p>403.5 禁止访问：需要使用 SSL 128 查看该资源。</p><p>403.6 禁止访问：客户端的 IP 地址被拒绝。</p><p>403.7 禁止访问：需要 SSL 客户端证书。</p><p>403.8 禁止访问：客户端的 DNS 名称被拒绝。</p><p>403.9 禁止访问：太多客户端试图连接到 Web 服务器。</p></div><div><p>403.10 禁止访问：Web 服务器配置为拒绝执行访问。</p><p>403.11 禁止访问：密码已更改。</p><p>403.12 禁止访问：服务器证书映射器拒绝了客户端证书访问。</p><p>403.13 禁止访问：客户端证书已在 Web 服务器上吊销。</p><p>403.14 禁止访问：在 Web 服务器上已拒绝目录列表。</p><p>403.15 禁止访问：Web 服务器已超过客户端访问许可证限制。</p><p>403.16 禁止访问：客户端证书格式错误或未被 Web 服务器信任。</p><p>403.17 禁止访问：客户端证书已经到期或者尚未生效。</p><p>403.18 禁止访问：无法在当前应用程序池中执行请求的 URL。</p><p>403.19 禁止访问：无法在该应用程序池中为客户端执行 CGI。</p><p>403.20 禁止访问：Passport 登录失败。</p><p>404 找不到文件或目录。</p><p>404.1 文件或目录未找到：网站无法在所请求的端口访问。</p><p>需要注意的是404.1错误只会出现在具有多个IP地址的计算机上。如果在特定IP地址/端口组合上收到客户端请求，而且没有将IP地址配置为在该特定的端口上侦听，则IIS返回 404.1 HTTP错误。例如，如果一台计算机有两个IP地址，而只将其中一个IP地址配置为在端口80上侦听，则另一个IP地址从端口80收到的任何请求都将导致IIS返回404.1错误。只应在此服务级别设置该错误，因为只有当服务器上使用多个IP地址时才会将它返回给客户端。</p><p>404.2 文件或目录无法找到：锁定策略禁止该请求。</p><p>404.3 文件或目录无法找到：MIME 映射策略禁止该请求。</p><p>405 用于访问该页的 HTTP 动作未被许可。</p><p>406 客户端浏览器不接受所请求页面的 MIME 类型。</p><p>407 Web 服务器需要初始的代理验证。</p><p>410 文件已删除。</p><p>412 客户端设置的前提条件在 Web 服务器上评估时失败。</p><p>414 请求 URL 太大，因此在 Web 服务器上不接受该 URL。</p><p>500 服务器内部错误。</p><p>500.11 服务器错误：Web 服务器上的应用程序正在关闭。</p><p>500.12 服务器错误：Web 服务器上的应用程序正在重新启动。</p><p>500.13 服务器错误：Web 服务器太忙。</p><p>500.14 服务器错误：服务器上的无效应用程序配置。</p><p>500.15 服务器错误：不允许直接请求 GLOBAL.ASA。</p><p>500.16 服务器错误：UNC 授权凭据不正确。</p><p>500.17 服务器错误：URL 授权存储无法找到。</p><p>500.18 服务器错误：URL 授权存储无法打开。</p><p>500.19 服务器错误：该文件的数据在配置数据库中配置不正确。</p><p>500.20 服务器错误：URL 授权域无法找到。</p><p>500 100 内部服务器错误：ASP 错误。</p><p>501 标题值指定的配置没有执行。</p><p>502 Web 服务器作为网关或代理服务器时收到无效的响应。</p></div><ul style="list-style-type: square;"><li>并发数分析</li></ul><p>　　　&#8220;Running Vusers（运行的并发数）&#8221;显示了在场景执行过程中并发数的执行情况。它们显示Vuser的状态、完成脚本的Vuser的数量以及集合统计信息，<span style="color: #0000ff;">将这些图与事务图结合使用可以确定Vuser的数量对事务响应时间产生的影响</span>。图1- 7显示了在OA系统考勤业务性能测试过程中Vusers运行情况，从图中我们可以看到，Vusers的运行趋势与我们场景执行计划中的设置是一样，表明在场景执行过程中，Vusers是按照我们预期的设置运行的，没有Vuser出现运行错误，这样从另一个侧面说明我们的参数化设置是正确的，因为使用唯一数进行参数化设置，如果设置不正确，将会导致Vuser运行错误。在脚本中我们加入了这样一段代码：</p><div><p>if (atoi(lr_eval_string("{num}")) &gt; 0){</p><p>              lr_output_message("登录成功，继续执行.");</p><p>              }</p><p>        else{</p><p>              lr_error_message("登录失败，退出测试");</p><p>              return -1;</p><p>        }</p></div><p>上述代码的意思是说，如果登录失败了，就退出脚本的迭代，那么什么原因可能会导致登录失败呢？就是我们前面参数化的设置，一旦Vuser分配不到正确的登录账号，就可能导致登录失败，从而引起Vuser停止运行。所以，从图5- 7的表现，可以认为参数化是没有问题的。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615112280.jpg" /></p><p> 图1- 7运行的并发数图</p><p>测试脚本中我们还使用了集合点，那么这里还可以看看集合点在场景执行过程中的表现，点击左边的&#8220;New Graph&#8221;，出现图5- 8，展开&#8220;Vusers&#8221;前的加号，双击&#8220;Rendezvous&#8221;，出现集合点的图形后，点击【Close】，关闭添加新图界面。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615123275.jpg" /></p><p> 图1- 8添加集合点统计图</p><p>集合点的图形如图1- 9所示，从图中可以看到，所有用户到达集合点后，立刻就释放了。与之前设定的集合点策略设置&#8220;所有运行用户到达后释放&#8220;是一致的。<span style="color: #0000ff;">假设这样的一种情况，Running的Vusers有10个，集合点策略设置是&#8220;所有运行用户到达后释放&#8221;，而集合点图形显示的最大释放Vusers是7个，那么就表示有些Vuser超时了，引起超时的原因可能是Vuser得到的响应超时了，可以结合平均事务响应时间再详细分析原因。</span></p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615141280.jpg" /></p><p> 图1- 9集合点状态图</p><p>我们本次测试Running Vusers与集合点是一致，说明整个场景执行过程中，并发数用户的执行正确，OA系统测试服务器能够应付7个并发用户的业务操作。</p><ul style="list-style-type: square;"><li>响应时间</li></ul><p>在性能测试要求中我们知道，有一项指标是要求登录、考勤业务操作的页面响应时间不超过3秒，那么本次测试是否达到了这个要求呢？我们先来看&#8220;Average Transaction Response Time（平均事务响应时间图）&#8221;（图1- 10），这张图是平均事务响应时间与结果摘要中的&#8220;Transaction Summary&#8221;合成的。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615154398.jpg" /></p><p> 图1- 10平均事务响应时间图</p><p>从图形下部我们可以看到，登录部分对应的Action是&#8220;submit_login&#8221;，考勤业务提交对应的Action是&#8220;submit_sign&#8221;，他们的&#8220;Average Time（平均响应时间为）&#8221;分别是4.425秒与0.848秒，从这两个数值来看，考勤业务的事务响应时间0.848秒小于预期的3秒，达到了要求，而登录是4.425秒，大于预期的3秒，不符合要求。这样的结果是不正确的，因为在统计的登录业务的时候，我们没有去除思考时间，所以，登录功能的实际事务时间应该是4.425秒-3秒=1.425秒，小于预期的3秒，故登录业务的事务响应时间也达到了我们的要求。<span style="color: #0000ff;">在平时的性能测试活动中，统计结果的时候需要去掉思考时间，加上思考时间是为了真实的模拟用户环境，统计结果中除去思考时间是为了更真实的反映服务器的处理能力，两者并不矛盾。</span></p><p>看完了&#8220;Average Time&#8221;，我们再看&#8220;90 Percent Time&#8221;，这个时间从某种程度来说，更准确衡量了测试过程中各个事务的真实情况，表示90%的事务，服务器的响应都维持在某个值附近，&#8220;Average Time&#8221;值对于平均事务响应时间变动趋势很大的情况统计就不准确了，比如有三个时间：1秒、5秒、12秒，则平均时间为6秒，而另外一种情况：5秒、6秒、7秒，平均时间也为6秒，显然第二种比第一种要稳定多了。所以，我们在查看平均事务响应时间的时候，先看整体曲线走势，如果整体趋势比较平滑，没有忽上忽下的波动情况，取&#8220;Average Time&#8221;与&#8220;90 Percent Time&#8221;都可以，如果整体趋势毫无规律，波动非常大，我们就不用&#8220;Average Time&#8221;而使用&#8220;90 Percent Time&#8221;可能更真实些。</p><p>从图5- 10可以看出，所有Action平均事务响应时间的趋势都非常平滑，所以使用&#8220;Average Time&#8221;与&#8220;90 Percent Time&#8221;差别不是很大，用哪个都可以。这里是使用最常用的统计方法&#8220;90 Percent Time&#8221;。登录业务的&#8220;90 Percent Time&#8221;是5.298秒-3秒（思考时间）=2.298秒，考勤业务的&#8220;90 Percent Time&#8221;是1.469秒，没有思考时间，那么就是实打实的啦。根据上面的计算，本次测试结果记录如表1所示。</p><div align="center"><table border="1" cellpadding="0" cellspacing="0"><tbody><tr><td valign="top"><p>测试项</p></td><td valign="top"><p>目标值</p></td><td valign="top"><p>实际值</p></td><td valign="top"><p>是否通过</p></td></tr><tr><td valign="top"><p>登录业务响应时间</p></td><td valign="top"><p>&lt;=3秒</p></td><td valign="top"><p>2.298秒</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>考勤业务响应时间</p></td><td valign="top"><p>&lt;=3秒</p></td><td valign="top"><p>1.469秒</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>登录业务成功率</p></td><td valign="top"><p>100%</p></td><td valign="top"><p> </p><br /></td><td valign="top"><p> </p><br /></td></tr><tr><td valign="top"><p>考勤业务成功率</p></td><td valign="top"><p>100%</p></td><td valign="top"><p> </p><br /></td><td valign="top"><p> </p><br /></td></tr><tr><td valign="top"><p>登录业务总数</p></td><td valign="top"><p>30分钟完成2000</p></td><td valign="top"><p> </p><br /></td><td valign="top"><p> </p><br /></td></tr><tr><td valign="top"><p>考勤业务总数</p></td><td valign="top"><p>30分钟完成2000</p></td><td valign="top"><p> </p><br /></td><td valign="top"><p> </p><br /></td></tr><tr><td valign="top"><p>CPU使用率</p></td><td valign="top"><p>&lt;75%</p></td><td valign="top"><p> </p><br /></td><td valign="top"><p> </p><br /></td></tr><tr><td valign="top"><p>内存使用率</p></td><td valign="top"><p>&lt;70%</p></td><td valign="top"><p> </p><br /></td><td valign="top"><p> </p><br /></td></tr></tbody></table></div><p>表1测试结果对照表一</p><p> </p><ul style="list-style-type: square;"><li>每秒点击数</li></ul><p>　　&#8220;Hits per Second（每秒点击数）&#8221;反映了客户端每秒钟向服务器端提交的请求数量，如果客户端发出的请求数量越多，与之相对的&#8220;Average Throughput (bytes/second)&#8221;也应该越大，并且发出的请求越多会对平均事务响应时间造成影响，所以在测试过程中往往将这三者结合起来分析。图1- 11显示的是&#8220;Hits per Second&#8221;与&#8220;Average Throughput(bytes/second)&#8221;的复合图，从图中可以看出，两种图形的曲线都正常并且基本一致，说明服务器能及时的接受客户端的请求，并能够返回结果。如果&#8220;Hits per Second&#8221;正常，而&#8220;Average Throughput (bytes/second)&#8221;不正常，则表示服务器虽然能够接受服务器的请求，但返回结果较慢，可能是程序处理缓慢。如果&#8220;Hits per Second&#8221;不正常，则说明客户端存在问题，那种问题一般是网络引起的，或者录制的脚本有问题，未能正确的模拟用户的行为。具体问题具体分析，这里仅给出一些建议。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615193979.jpg" /></p><p> 图1- 11每秒点击数与每秒吞吐量复合图</p><p>对于本次测试来说，&#8220;Hits per Second&#8221;与&#8220;Average Throughput (bytes/second)&#8221;都是正常的，而且整体表现还是不错的。</p><p>一般情况下，这两种指标用于性能调优，比如给定了几个条件，去检测另外一个条件，用这两个指标衡量，往往起到很好的效果。比如要比较某两种硬件平台的优劣，就可以使用相同的配置方法部署软件系统，然后使用相同的脚本、场景设计、统计方法去分析，最终得出一个较优的配置。</p><ul style="list-style-type: square;"><li>业务成功率</li></ul><p>　　&#8220;业务成功率&#8221;这个指标在很多系统中都提及到，比如电信的、金融的、企业资源管理的等等。举个例子，我们楼下的建行，假如每天的业务类别是这样的：20个开户，5个销户，300个存款，500取款，100个汇款等，那么在做他们的营业系统测试时就需要考虑业务成功率了，一般不得低于98%。具体的业务成功率是什么意思呢？排除那些复杂的业务，比如异步处理的业务（移动的套卡开通就是异步的），业务成功率就是事务成功率，用户一般把一个Aciton当做一笔业务，在LoadRunner场景执行中一笔交易称为一个事务。所以，说业务成功率其实就是事务成功率、通过率的意思。在&#8220;Transaction Summary&#8221;中我们可以很明确的看到每个事务的执行状态，如图1- 12所示。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615212646.jpg" /></p><p> 图1- 12事务状态统计图</p><p>从图中可以看出，所有的Aciton都是绿色的，即表示为Passed，同时除了vuser_init与vuser_end两个事务，其他的事务通过数为2163，也就表明在30分钟的时间里，共完成了2163次登录考勤业务操作。那么根据这些可以判断本次测试登录业务与考勤业务的成功率是100%，再次更新测试结果记录表如表2所示。</p><div align="center"><table border="1" cellpadding="0" cellspacing="0"><tbody><tr><td valign="top"><p>测试项</p></td><td valign="top"><p>目标值</p></td><td valign="top"><p>实际值</p></td><td valign="top"><p>是否通过</p></td></tr><tr><td valign="top"><p>登录业务响应时间</p></td><td valign="top"><p>&lt;=3秒</p></td><td valign="top"><p>2.298秒</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>考勤业务响应时间</p></td><td valign="top"><p>&lt;=3秒</p></td><td valign="top"><p>1.469秒</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>登录业务成功率</p></td><td valign="top"><p>100%</p></td><td valign="top"><p>100%</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>考勤业务成功率</p></td><td valign="top"><p>100%</p></td><td valign="top"><p>100%</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>登录业务总数</p></td><td valign="top"><p>30分钟完成2000</p></td><td valign="top"><p>2163</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>考勤业务总数</p></td><td valign="top"><p>30分钟完成2000</p></td><td valign="top"><p>2163</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>CPU使用率</p></td><td valign="top"><p>&lt;75%</p></td><td valign="top"><p> </p><br /></td><td valign="top"><p> </p><br /></td></tr><tr><td valign="top"><p>内存使用率</p></td><td valign="top"><p>&lt;70%</p></td><td valign="top"><p> </p><br /></td><td valign="top"><p> </p><br /></td></tr></tbody></table></div><p>表2测试结果对照表二</p><p> </p><ul style="list-style-type: square;"><li>系统资源</li></ul><p>　　　系统资源图显示了在场景执行过程中被监控的机器系统资源使用情况，一般情况下监控机器的CPU、内存、网络、磁盘等各个方面。本次测试监控的是测试服务器的CPU使用率与内存使用率，以及处理器队列长度，具体的数据如图1- 13所示。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615233548.jpg" /></p><p> 图1- 13测试服务器系统资源监控结果图</p><p>从图中可以看出，CPU使用率、可用物理内存、CPU的队列长度三个指标的曲线逗较为平滑，三者的平均值分别为：53.582%、83.456M、8.45，而测试服务器总的物理内存为384M，那么内存使用率为（384-83.456）/384=78.26%，根据本次性能测试要求的：CPU使用率不超过75%，物理内存使用率不超过70%这两点来看，内存的使用率78.26%大于预期的70%，故内存使用率不达标。根据Windwos资源性能指标的解释，一般情况下，如果&#8220;Processor Queue Length（处理器队列长度）&#8221;一直超过二，则可能表示处理器堵塞，我们这里监控出来的数值是8.45，而且总体上保持平衡，那么由此推断，测试服务器的CPU也可能是个瓶颈。同时在测试过程中，场景执行到23分半钟的时候，报出了<strong>错误！未找到引用源。</strong>的错误，意思是说被监控的服务器当前无法再进行计数器数据的获取了，所以，本次操作系统资源的监控只得到了场景执行的前23分半钟的数据。这样对本次测试结果有一定的影响。</p><p>获得上述数据后，最新的测试结果记录表如表3所示。</p><div align="center"><table border="1" cellpadding="0" cellspacing="0"><tbody><tr><td valign="top"><p>测试项</p></td><td valign="top"><p>目标值</p></td><td valign="top"><p>实际值</p></td><td valign="top"><p>是否通过</p></td></tr><tr><td valign="top"><p>登录业务响应时间</p></td><td valign="top"><p>&lt;=3秒</p></td><td valign="top"><p>2.298秒</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>考勤业务响应时间</p></td><td valign="top"><p>&lt;=3秒</p></td><td valign="top"><p>1.469秒</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>登录业务成功率</p></td><td valign="top"><p>100%</p></td><td valign="top"><p>100%</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>考勤业务成功率</p></td><td valign="top"><p>100%</p></td><td valign="top"><p>100%</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>登录业务总数</p></td><td valign="top"><p>30分钟完成2000</p></td><td valign="top"><p>2163</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>考勤业务总数</p></td><td valign="top"><p>30分钟完成2000</p></td><td valign="top"><p>2163</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>CPU使用率</p></td><td valign="top"><p>&lt;75%</p></td><td valign="top"><p>53.582%</p></td><td valign="top"><p>Y</p></td></tr><tr><td valign="top"><p>内存使用率</p></td><td valign="top"><p>&lt;70%</p></td><td valign="top"><p>78.26%</p></td><td valign="top"><p>N</p></td></tr></tbody></table></div><p>表3测试结果对照表三</p><p>从上表数据来看，本次测试总体上已经达到了预期的性能指标，但从其他的数据，比如CPU的队列长度、内存使用率来看，被测服务器的硬件资源需要提升。</p><ul style="list-style-type: square;"><li>网页细分图</li></ul><p>　　　网页细分图可以评估页面内容是否影响事务响应时间。使用网页细分图，可以分析网站上有问题的元素（例如下载很慢的图像或打不开的链接）。</p><p>我们这里查看一下网页细分图中的&#8220;Page Download Time Breakdown&#8221;，点击<strong>错误！未找到引用源。</strong>左边的&#8220;New Graph&#8221;，出现图1- 14，展开&#8220;Web Page Diagnostics&#8221;前的加号，双击&#8220;Page Download Time Breakdown&#8221;，待出现&#8220;Page Download Time Breakdown&#8221;监控图后，点击【Close】按钮关闭添加监控图界面。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615264084.jpg" /></p><p> 图1- 14添加网页细分图</p><p>在监控图列表中，我们看到图1- 15，从图中我们看到，在所有的页面中，登录后的用个人面页面&#8220;http://192.168.0.52:8080/oa/oa.jsp&#8221;的下载时间最长。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615281537.jpg" /></p><p> </p><p>图1- 15网页下载时间细分图</p><p>图1- 16详细列出了每个页面所消耗的时间分布，图中每一个指标含义见表4所示。该表由LoadRunner使用手册提供。通过这些指标的数据，我们可以轻易的判断是哪个页面、哪个请求导致了响应时间变长，甚至响应失败。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615292648.jpg" /></p><p> </p><p>图1- 16 oa.jsp页面下载时间分布图</p><div align="center"><table border="1" cellpadding="0" cellspacing="0"><tbody><tr><td valign="top"><p>名称</p></td><td valign="top"><p>描述</p></td></tr><tr><td valign="top"><p>Client Time</p></td><td valign="top"><p>显示因浏览器思考时间或其他与客户端有关的延迟而使客户机上的请求发生延迟时，所经过的平均时间。</p></td></tr><tr><td valign="top"><p>Connection Time</p></td><td valign="top"><p>显示与包含指定URL的Web服务器建立初始连接所需的时间。连接度量是一个很好的网络问题指示器。此外，它还可表明服务器是否对请求做出响应。</p></td></tr><tr><td valign="top"><p>DNS Resolution Time</p></td><td valign="top"><p>显示使用最近的DNS服务器将DNS名称解析为IP地址所需的时间。DNS查找度量是指示 DNS解析问题或DNS服务器问题的一个很好的指示器。</p></td></tr><tr><td valign="top"><p>Error Time</p></td><td valign="top"><p>显示从发出HTTP请求到返回错误消息（仅限于HTTP错误）这期间经过的平均时间。</p></td></tr><tr><td valign="top"><p>First Buffer Time</p></td><td valign="top"><p>显示从初始HTTP请求（通常为GET）到成功收回来自Web服务器的第一次缓冲时为止所经过的时间。第一次缓冲度量是很好的Web 服务器延迟和网络滞后指示器。</p><p>（注意：由于缓冲区大小最大为8K，因此第一次缓冲时间可能也就是完成元素下载所需的时间。）</p></td></tr><tr><td valign="top"><p>FTP Autherntication Time</p></td><td valign="top"><p>显示验证客户端所用的时间。如果使用 FTP，则服务器在开始处理客户端命令之前，必须验证该客户端。FTP验证度量仅适用于 FTP协议通信</p></td></tr><tr><td valign="top"><p>Receive Time</p></td><td valign="top"><p>显示从服务器收到最后一个字节并完成下载之前经过的时间。接收度量是很好的网络质量指示器（查看用来计算接收速率的时间 / 大小比率）。</p></td></tr><tr><td valign="top"><p>SSL Handshaking Time</p></td><td valign="top"><p>显示建立SSL连接（包括客户端hello、服务器hello、客户端公用密钥传输、服务器证书传输和其他部分可选阶段）所用的时间。此时刻后，客户端和服务器之间的所有通信都被加密。SSL握手度量仅适用于HTTPS通信。</p></td></tr></tbody></table></div><p>表4网页下载时间细分指标说明</p><p>对于本次测试，从网页细分图来看，基本上每个页面的加载时间都是预期范围内，oa.jsp页面因为集成了用户的个人工作平台，需要检索很多的数据，并合成了很多图片，所以相应的加载时间较长，这是正确的。</p><ul style="list-style-type: square;"><li>Web服务器资源</li></ul><p>　　　上述所有的监控图形LoadRunner都可以提供，但对于某些测试监控图来说，LoadRunner就没有提供了，期望其新版支持这些功能，当然想监控Tomcat、Jboss或者其他的Web服务器可以SiteScope工具，这个工具配置较为复杂，根据个人需要吧。我这里监控Tomcat使用的是ManageEngine Applications Manager 8的试用版，测试结束后得出Tomcat的JVM使用率如图1- 17所示。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615314339.jpg" /></p><p> </p><p>图1- 17 Tomcat JVM使用率监视图</p><p>从图中我们可以明显看出，Tomcat的JVM使用率不断上升，配置Tomcat时共分配了100M左右的物理内存给其，测试初期使用的JVM相对来说较少，我们的测试场景是从15:58:40开始，到16:29:42结束，共历时31分2秒。从图中看到，从16:00到16:30这个时间内，也就是测试场景执行期间，JVM的使用率不断上升，并没有在请求达到均衡状态后也呈现一种平衡状态，所以，从这点可以推断，如果测试场景继续执行，或者加大并发数，最终必将导致Tomcat内存不够用而报出&#8220;Out Of Memory&#8221;内存溢出的错误。在正常情况下，内存的使用应该与&#8220;Hit per Second&#8221;、&#8220;Average Throughput (bytes/second)&#8221;等监控图的图形走势是一致的。</p><p>从上述过程可以得出一个结论，出现图1- 17中的问题，可能有两个原因：</p><p>1、  Tomcat的内存分配不足；</p><p>2、  程序代码有错误，可能导致内存泄露。</p><p>解决方法：</p><p align="left">1、  为Tomcat分配更多的内存，如果是使用的catalina.sh或Catalina.bat启动的Tomcat，则可在这两个文件中添加&#8220;SET CATALINA_OPTS= -Xms300m&#8211;Xmx300m&#8221;，如果使用的winnt服务方式启动的Tomcat，则可在&#8220;运行&#8221;中输入&#8220;regedit&#8221;进入注册表，然后在&#8220;HKEY_LOCAL_MACHINE--&gt;SOFTWARE--&gt;Apache Software Foundation--&gt;Process Runner 1.0--&gt;Tomcat5--&gt;Parameters&#8221;修改两个属性，一个是JvmMs，另外一个是JvmMx，如图1- 18所示。</p><p align="left">2、  检查程序代码，使用一些内存泄露检查工具进行清查。</p><p><img alt="" src="http://pic002.cnblogs.com/images/2011/342452/2011111615323029.jpg" /></p><p> 图1- 18修改Tocat的JVM数据</p><p> </p><ul style="list-style-type: square;"><li>数据库服务器资源</li></ul><p>数据库服务器资源监控相对来说就复杂的多了，现在常用的数据有Mysql、SQL Server、Oracle、DB2等，LoadRunner提供对后面几种数据库的监控方法，但对Mysql没有提供对应的监控方法。他不提供，咱们就自己找监控工具，我这里使用的是Spotlight，该工具监控数据库的好处是配置连接简单，不仅能监控数据库，还能监控操作系统的资源，监控结果直观明了。<strong>错误！未找到引用源。</strong>显示了Mysql数据库在场景执行过程中SQL语句的执行情况，从图中可以看到，&#8220;Selects（查询）&#8221;与&#8220;Inserts（插入）&#8221;两种语句执行的趋势在场景执行过程中是比较平滑，并且测试中没有错误发现，也就说明在处理相关业务时Mysql的处理是正常的。假如这两种SQL语句任何一个出现波动很大的情况，就可以推出在场景执行过程中存在页面错误，因为这些语句不执行，就表明某些页面未被加载或者某些功能未被使用。在本次测试中，OA系统的&#8220;oa.jsp&#8221;页面有大量的&#8220;Selects（查询）&#8221;语句，而考勤操作则是&#8220;Inserts（插入）&#8221;，所以，只要有一方出问题，必然表示测试过程中存在页面打不开或者考勤不成功的错误。</p><p>通过前面的分析，在查看<strong>错误！未找到引用源。</strong>中的SQL语句执行状态，本次测试在页面访问、功能执行方面是没有问题的。</p></div><img src ="http://www.cnitblog.com/stomic/aggbug/88829.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-11-19 15:06 <a href="http://www.cnitblog.com/stomic/archive/2013/11/19/88829.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LoadRunner监控SQLServer  </title><link>http://www.cnitblog.com/stomic/archive/2013/11/17/88823.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Sun, 17 Nov 2013 02:08:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/11/17/88823.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/88823.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/11/17/88823.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/88823.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/88823.html</trackback:ping><description><![CDATA[<h3 class="title pre fs1"><span class="tcnt"><font size="6">LoadRunner监控SQLServer</font></span> <span class="bgc0 fc07 fw0 fs0"></span></h3>
<p style="line-height: 20px" class="tdep clearfix nbw-act fc06"><span class="pleft"><span class="blogsep">2011-03-21 15:37:38</span><span class="blogsep">| 分类：</span> <a class="fc03 m2a" title="性能测试" href="http://sujing1981.blog.163.com/blog/#m=0&amp;t=1&amp;c=fks_084065080083087067084095084095086081081065081087082070"><u><font color="#0066cc">性能测试</font></u></a> <span id="$_blogTagTitle" class="blogsep phide">| 标签：</span><span id="$_blogTagInfo" class="fc03 phide"></span> </span><span class="pright fc07 ztag"><span class="blogsep">|</span><span id="$_fontswitch" class="zihao fc03" __1384653979701__="ev_6021359222">字号<span id="$_fontsTypes" class="zihaoshow  phide"><span class="zihaoc bdc0"><span class="stag" index="0" __1384653979701__="ev_6229399730" __tabkey__="true"></span><span class="fc04 stag" index="1" __1384653979701__="ev_6837622016" __tabkey__="true">大</span><span class="fc04 stag selected js-fcurrent fc05" index="2" __1384653979701__="ev_1070707812" __tabkey__="true">中</span><span class="fc04 stag" index="3" __1384653979701__="ev_8267270652" __tabkey__="true">小</span></span></span></span></span><span id="$_blog_subscribe" class="pright pnt fc03" __1384653979701__="ev_3769496389"><span class="iblock icn0 icn0-919"> </span><a class="m2a">订阅</a></span> </p>
<div></div>
<div class="nbw-blog-start"></div>
<div class="bct fc05 fc11 nbw-blog ztag js-fs2">
<p><wbr>监控SQLSERVER时，能增加度量。但是只有系统资源相关的度量有数据，而和sqlserver相关的度量却没有数据。</p>
<p>解决方法：</p>
<p>改为在System Resource Graphs中通过添加Windows Resources的方式添加SQLServer计数器则可以，添加的对象是SQLServer:General Statistics，计数器选User Connections</p>
<p>应该收集哪些SQLServer的性能指标？<br />一般需要监控以下指标：</p>
<p>1） SQLServer资源监控中指标缓存点击率（Cache Hit Ratio），该值越高越好。如果持续低于80%，应考虑增加内存。</p>
<p>2） 如果Full Scans/sec（全表扫描/秒）计数器显示的值比1或2高，则应分析你的查询以确定是否确实需要全表扫描，以及SQL查询是否可以被优化。</p>
<p>3） Number of Deadlocks/sec(死锁的数量/秒)：死锁对应用程序的可伸缩性非常有害，并且会导致恶劣的用户体验。该计数器的值必须为0。</p>
<p>4） Lock Requests/sec(锁请求/秒)，通过优化查询来减少读取次数，可以减少该计数器的值。</p>
<p>具体可参考：</p>
<p>1、Controller帮助文档：</p>
<p>The following table describes the default counters that can be monitored on version 6.5 of the SQL Server: </p>
<p>Measurement <br />Description <br /><br />% Total Processor Time (NT) <br />The average percentage of time that all the processors on the system are busy executing non-idle threads. On a multi-processor system, if all processors are always busy, this is 100%, if all processors are 50% busy this is 50% and if 1/4 of the processors are 100% busy this is 25%. It can be viewed as the fraction of the time spent doing useful work. Each processor is assigned an Idle thread in the Idle process which consumes those unproductive processor cycles not used by any other threads. <br /><br />% Processor Time (Win 2000) <br />The percentage of time that the processor is executing a non-idle thread. This counter was designed as a primary indicator of processor activity. It is calculated by measuring the time that the processor spends executing the thread of the idle process in each sample interval, and subtracting that value from 100%. (Each processor has an idle thread which consumes cycles when no other threads are ready to run). It can be viewed as the percentage of the sample interval spent doing useful work. This counter displays the average percentage of busy time observed during the sample interval. It is calculated by monitoring the time the service was inactive, and then subtracting that value from 100%. <br /><br />Cache Hit Ratio <br />The percentage of time that a requested data page was found in the data cache (instead of being read from disk). <br /><br />I/O - Batch Writes/sec <br />The number of 2K pages written to disk per second, using Batch I/O. The checkpoint thread is the primary user of Batch I/O. <br /><br />I/O - Lazy Writes/sec <br />The number of 2K pages flushed to disk per second by the Lazy Writer. <br /><br />I/O - Outstanding Reads <br />The number of physical reads pending. <br /><br />I/O - Outstanding Writes <br />The number of physical writes pending. <br /><br />I/O - Page Reads/sec <br />The number of physical page reads per second. <br /><br />I/O - Transactions/sec <br />The number of Transact-SQL command batches executed per second. <br /><br />User Connections <br />The number of open user connections. <br /></p>
<p>2、《Performance Monitoring Best Practices》中的MS SQL Server Monitoring部分。</p>
<p>安装LR9.51补丁后可以在C:\Program Files\HP\LoadRunner\help目录中找到Monitoring_BP.pdf文件。</p>
<p>3、参考：</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/zhone/archive/2010/12/13/6073808.aspx" rel="nofollow"><u><font color="#0066cc">http://blog.csdn.net/zhone/archive/2010/12/13/6073808.aspx</font></u></a></p>
<p><u><font color="#0066cc"></font></u></p>
<p><span style="line-height: 26px; font-family: 宋体; font-size: 14px"></span><span style="line-height: 26px; font-family: 宋体; font-size: 14px"></span><span style="line-height: 26px; font-family: 宋体; font-size: 14px"></span>
<table style="line-height: 26px; font-family: 宋体; font-size: 12px" border="1" frame="border">
<tbody>
<tr>
<td style="font-size: 12px">性能计数器:</td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px">Performance Object</td>
<td style="font-size: 12px">Counter</td>
<td style="font-size: 12px">Description</td></tr>
<tr>
<td style="font-size: 12px" rowspan="2">Processor</td>
<td style="font-size: 12px">%processor Time</td>
<td style="font-size: 12px">指处理器执行非闲置线程时间的百分比,测量处理器繁忙的时间 这个计数器设计成用来作为处理器活动的主要指示器,可以选择单个CPU实例,也可以选择Total</td></tr>
<tr>
<td style="font-size: 12px">Interrupts/sec</td>
<td style="font-size: 12px">处理器正在处理的来自应用程序或硬件的中断的数量</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="5">PhysicalDisk</td>
<td style="font-size: 12px">% Disk Time</td>
<td style="font-size: 12px">
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" id="_mcePaste">计数器监视磁盘忙于读/写活动所用时间的百分比.在系统监视器中，PhysicalDisk: % Disk Time 计数器监视磁盘忙于读/写活动所用时间的百分比。如果 PhysicalDisk: % Disk Time 计数器的值较高（大于 90%），请检查 PhysicalDisk: Current Disk Queue Length 计数器了解等待进行磁盘访问的系统请求数量。等待 I/O 请求的数量应该保持在不超过组成物理磁盘的轴数的 1.5 到 2 倍。大多数磁盘只有一个轴，但独立磁盘冗余阵列 (RAID) 设 备通常有多个轴。硬件 RAID 设备在系统监视器中显示为一个物理磁盘。通过软件创建的多个 RAID 设备在系统监视器中显示为多个实例。</div>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" id="_mcePaste">可以使用 Current Disk Queue Length 和 % Disk Time 计数器的值检测磁盘子系统中的瓶颈。如果 Current Disk Queue Length 和 % Disk Time 计数器的值一直很高，则考虑下列事项：</div>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" id="_mcePaste">1.使用速度更快的磁盘驱动器。</div>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" id="_mcePaste">2.将某些文件移至其他磁盘或服务器。</div>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" id="_mcePaste">3.如果正在使用一个 RAID 阵列，则在该阵列中添加磁盘。</div>计数器监视磁盘忙于读/写活动所用时间的百分比.在系统监视器中，PhysicalDisk: % Disk Time 计数器监视磁盘忙于读/写活动所用时间的百分比。<br />如果 PhysicalDisk: % Disk Time 计数器的值较高（大于 90%），请检查 PhysicalDisk: Current Disk Queue Length 计数器了解等待进行磁<br />盘访问的系统请求数量。等待 I/O 请求的数量应该保持在不超过组成物理磁盘的轴数的 1.5 到 2 倍。大多数磁盘只有一个轴，但独立磁盘冗余阵列 <br />(RAID) 设备通常有多个轴。硬件 RAID 设备在系统监视器中显示为一个物理磁盘。通过软件创建的多个 RAID 设备在系统监视器中显示为多个实例。<br />可以使用 Current Disk Queue Length 和 % Disk Time 计数器的值检测磁盘子系统中的瓶颈。如果 Current Disk Queue Length 和 % Disk Time 计数器的值一直很高，则考虑下列事项：<br />1.使用速度更快的磁盘驱动器。<br />2.将某些文件移至其他磁盘或服务器。<br />3.如果正在使用一个 RAID 阵列，则在该阵列中添加磁盘。</td></tr>
<tr>
<td style="font-size: 12px">Avg.Disk Queue Length</td>
<td style="font-size: 12px">指读取和写入请求(为所选磁盘在实例间隔中列队的)的平均数</td></tr>
<tr>
<td style="font-size: 12px">Current Disk Queue Length</td>
<td style="font-size: 12px">指示被挂起的磁盘 I/O 请求的数量。如果这个值始终高于 2， 就表示产生了拥塞</td></tr>
<tr>
<td style="font-size: 12px">Avg.Disk Bytes/Transfer</td>
<td style="font-size: 12px">写入或读取操作时向磁盘传送或从磁盘传出字节的平均数</td></tr>
<tr>
<td style="font-size: 12px">Disk Bytes/sec</td>
<td style="font-size: 12px">在读写操作中，从磁盘传出或传送到磁盘的字节速率</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="5">Memory</td>
<td style="font-size: 12px">Pages/sec</td>
<td style="font-size: 12px">被请求页面的数量.</td></tr>
<tr>
<td style="font-size: 12px">Available Bytes</td>
<td style="font-size: 12px">可用物理内存的数量</td></tr>
<tr>
<td style="font-size: 12px">Committed Bytes</td>
<td style="font-size: 12px">已分配给物理 RAM 用于存储或分配给页面文件的虚拟内存</td></tr>
<tr>
<td style="font-size: 12px">Pool Nonpaged Bytes</td>
<td style="font-size: 12px">未分页池系统内存区域中的 RAM 数量</td></tr>
<tr>
<td style="font-size: 12px">Page Faults/sec</td>
<td style="font-size: 12px">是每秒钟出错页面的平均数量</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="3">Network Interface</td>
<td style="font-size: 12px">Bytes Received/sec</td>
<td style="font-size: 12px">使用本网络适配器接收的字节数</td></tr>
<tr>
<td style="font-size: 12px">Bytes Sent/sec</td>
<td style="font-size: 12px">使用本网络适配器发送的字节数</td></tr>
<tr>
<td style="font-size: 12px">Bytes Total/sec</td>
<td style="font-size: 12px">使用本网络适配器发送和接收的字节数</td></tr>
<tr>
<td style="font-size: 12px">Server</td>
<td style="font-size: 12px">Bytes Received/sec</td>
<td style="font-size: 12px">把此计数器与网络适配器的总带宽相比较，确定网络连接是否产生瓶颈</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="3">SQL Server Access Methods</td>
<td style="font-size: 12px">Page Splits/sec</td>
<td style="font-size: 12px">每秒由于索引页溢出而发生的页拆分数.如果发现页分裂的次数很多,考虑提高Index的填充因子.数据页将会有更多的空间保留用于做数据的填充,从而减少页拆分</td></tr>
<tr>
<td style="font-size: 12px">Pages Allocated/sec</td>
<td style="font-size: 12px">在此 SQL Server 实例的所有数据库中每秒分配的页数。这些页包括从混合区和统一区中分配的页</td></tr>
<tr>
<td style="font-size: 12px">Full Scans/sec</td>
<td style="font-size: 12px">每秒不受限制的完全扫描数. 这些扫描可以是基表扫描，也可以是全文索引扫描</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="3">SQL Server: SQL Statistics</td>
<td style="font-size: 12px">Batch Requests/Sec</td>
<td style="font-size: 12px">每秒收到的 Transact-SQL 命令批数。这一统计信息受所有约束（如 I/O、用户数、高速缓存大小、请求的复杂程度等）影响。<br />批处理请求数值高意味着吞吐量</td></tr>
<tr>
<td style="font-size: 12px">SQL Compilations/Sec</td>
<td style="font-size: 12px">每秒的编译数。表示编译代码路径被进入的次数。包括 SQL Server 中语句级重新编译导致的编译。当 SQL Server 用户活动稳定后，<br />该值将达到稳定状态</td></tr>
<tr>
<td style="font-size: 12px">Re-Compilations/Sec</td>
<td style="font-size: 12px">每秒语句重新编译的次数。计算语句重新编译被触发的次数。一般来说，这个数最好较小,存储过程在理想情况下应该只编译一次，<br />然后执行计划被重复使用. 如果该计数器的值较高，或许需要换个方式编写存储过程，从而减少重编译的次数</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="3">SQL Server: Databases</td>
<td style="font-size: 12px">Log Flushes/sec</td>
<td style="font-size: 12px">每秒日志刷新数目</td></tr>
<tr>
<td style="font-size: 12px">Active Transactions</td>
<td style="font-size: 12px">数据库的活动事务数</td></tr>
<tr>
<td style="font-size: 12px">Backup/Restore Throughput/sec</td>
<td style="font-size: 12px">每秒数据库的备份和还原操作的读取/写入吞吐量。例如，并行使用多个备份设备或使用更快的设备时,可以测量数据库备份操作性能的变化情况。<br />数据库的备份或还原操作的吞吐量可以确定备份和还原操作的进程和性能</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="3">SQL Server General Statistics</td>
<td style="font-size: 12px">User Connections</td>
<td style="font-size: 12px">系统中活动的SQL连接数. 该计数器的信息可以用于找出系统的最大并发用户数</td></tr>
<tr>
<td style="font-size: 12px">Temp Tables Creation Rate</td>
<td style="font-size: 12px">每秒创建的临时表/表变量的数目</td></tr>
<tr>
<td style="font-size: 12px">Temp Tables For Destruction</td>
<td style="font-size: 12px">等待被清除系统线程破坏的临时表/表变量数</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="3"><br />SQL Server Locks</td>
<td style="font-size: 12px">Number of Deadlocks/sec</td>
<td style="font-size: 12px">指每秒导致死锁的锁请求数. 死锁对于应用程序的可伸缩性非常有害, 并且会导致恶劣的用户体验. 该计数器必须为0</td></tr>
<tr>
<td style="font-size: 12px">Average Wait Time (ms)</td>
<td style="font-size: 12px">每个导致等待的锁请求的平均等待时间</td></tr>
<tr>
<td style="font-size: 12px">Lock requests/sec</td>
<td style="font-size: 12px">锁管理器每秒请求的新锁和锁转换数. 通过优化查询来减少读取次数, 可以减少该计数器的值</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="4">SQL Server:Memory Manager</td>
<td style="font-size: 12px">Total Server Memory (KB)</td>
<td style="font-size: 12px">从缓冲池提交的内存(这不是 SQL Server 使用的总内存)</td></tr>
<tr>
<td style="font-size: 12px">Target Server Memory (KB)</td>
<td style="font-size: 12px">服务器能够使用的动态内存总量</td></tr>
<tr>
<td style="font-size: 12px">SQL Cache Memory(KB)</td>
<td style="font-size: 12px">服务器正在用于动态 SQL 高速缓存的动态内存总数</td></tr>
<tr>
<td style="font-size: 12px">Memory Grants Pending</td>
<td style="font-size: 12px">指每秒等待工作空间内存授权的进程数. 该计数器应该尽可能接近0,否则预示可能存在着内存瓶颈</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td></tr>
<tr>
<td style="font-size: 12px" rowspan="6">SQL Server Buffer Manager</td>
<td style="font-size: 12px">Buffer Cache Hit Ratio</td>
<td style="font-size: 12px">缓存命中率,在缓冲区高速缓存中找到而不需要从磁盘中读取(物理I/O)的页的百分比. 如果该值较低则可能存在内存不足或不正确的索引</td></tr>
<tr>
<td style="font-size: 12px">Page Reads/sec</td>
<td style="font-size: 12px">每秒发出的物理数据库页读取数。此统计信息显示的是所有数据库间的物理页读取总数。由于物理 I/O 的开销大，可以通过使用更大的数据缓存、智能索引、更有效的查询或更改数据库设计等方法，将开销降到最低</td></tr>
<tr>
<td style="font-size: 12px">Page Writes/sec</td>
<td style="font-size: 12px">每秒执行的物理数据库页写入数</td></tr>
<tr>
<td style="font-size: 12px">Page Life Expectancy</td>
<td style="font-size: 12px">页若不被引用将在缓冲池中停留的秒数</td></tr>
<tr>
<td style="font-size: 12px">Lazy Writes/Sec</td>
<td style="font-size: 12px">每秒被缓冲区管理器的惰性编写器写入的缓冲区数</td></tr>
<tr>
<td style="font-size: 12px">Checkpoint Pages/Sec</td>
<td style="font-size: 12px">由要求刷新所有脏页的检查点或其他操作每秒刷新到磁盘的页数</td></tr>
<tr>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"></td>
<td style="font-size: 12px"><br /></td></tr></tbody></table></p></div><img src ="http://www.cnitblog.com/stomic/aggbug/88823.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-11-17 10:08 <a href="http://www.cnitblog.com/stomic/archive/2013/11/17/88823.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转）LoadRunner中进程运行和线程运行区别</title><link>http://www.cnitblog.com/stomic/archive/2013/07/29/88200.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Mon, 29 Jul 2013 09:16:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2013/07/29/88200.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/88200.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2013/07/29/88200.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/88200.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/88200.html</trackback:ping><description><![CDATA[<div>　<a target="_self"><u><strong>LoadRunner</strong></u></a> controller将使用驱动程序mmdrv运行Vuser。用户可以在controller的run-time setting中选择Vuser的运行方式， 是多进程方式or多线程方式。<p>　　如果选择以线程方式来运行虚拟用户：</p><p>　　在场景设置时，&#8220;是单行脚本，还是多行脚本&#8221;会决定系统启动的进程数的多少：假设并发用户设置为30，如果是单行30个用户，系统只需启动一个进程；假设并发用户设置为30，如果是多行，30行，每行一个用户，系统就需要启动30个进程；</p><p>　　如果选择以进程方式来运行虚拟用户：</p><p>　　那么无论脚本在场景组中怎么设置，是单行多用户还是多行少用户方式，系统需要启动的进程数是一定的，就是并发用户的总数；</p><p>　　进程方式和线程方式的优缺点：</p><p>　 　如果选择按照进程方式运行，每个用户都将启动一个mmdrv进程，多个mmdrv进程会占用大量内存及其他系统资源，这就限制了可以在任一负载生成器上 运行的并发用户数的数量，因为负载机的资源（内存及其他系统资源）是有限的。如果选择按照线程方式运行，在默认情况下，controller为每50个用 户仅启动一个mmdrv进程，而每个用户都按线程方式来运行，这些线程用户将共享父进程的内存段，这就节省了大量内存空间，从而可以在一个负载生成器上运 行更多的用户。（如果选择线程方式来运行用户，每个进程中会多出几个线程，例如是53个，多出来的进程可能是用于维护进程之间的运行的）选择线程方式虽然 可以减少启动的mmdrv进程数，减少了内存的占用，但是也容易出现一个问题，例如，同一个<a target="_self"><u><strong>测试</strong></u></a>场景，用线程并发就会出现超时失败或报错，而用进程并发就没错。为什么呢？因为线程的资源是从进程资源中分配出来的，因此同一个进程中的多个线程会有共享的内存空间，假设a线程要用资源就必须等待b线程释放，而b线程也在等待其他资源释放才能继续，这样就会出现这个问题。</p><p>　　系统需要启动的mmdrv进程数与哪些因素有关：</p><p>　 　与在controller  的运行时设置中选择的是进程方式or线程方式来运行虚拟用户有关进程方式：无论是单行or多行脚本，需要启动的进程数就是并发用户数；线程方式：假设是单 行脚本，每50个用户才启动一个进程；多行脚本，有几行（每行&lt;50人）就启动几个进程，而不是每个用户启动一个进程。如果选择了线程方式，需启动 的进程数，进一步还与脚本是单行还是多行有关单行脚本，多用户，假设少于50，只需启动一个进程，100个用户，只需启动2个进程，依此类推；多行脚本， 即使每行一个用户，也需要启动一个进程，多一行就需要多启动一个进程；不是每个用户启动一个进程，有几行（每行&lt;50人）就需要启动几个进程。在启 动了IP欺骗功能后，所需启动的进程数，还与选择的是按进程还是按线程来分配IP地址有关按进程分IP：每个ip（负载生成器）就需要多启动一个进程；  按线程分IP：每个ip（负载生成器）不需要多启动一个进程。</p></div><img src ="http://www.cnitblog.com/stomic/aggbug/88200.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2013-07-29 17:16 <a href="http://www.cnitblog.com/stomic/archive/2013/07/29/88200.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Load Agent and Load Controller Installation and Configuration Guide</title><link>http://www.cnitblog.com/stomic/archive/2011/05/12/73524.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Thu, 12 May 2011 03:37:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2011/05/12/73524.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/73524.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2011/05/12/73524.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/73524.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/73524.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: The Team Test Rig enables Team System users to run tests on one ormore remote computers. A rig is made up of a single test controller and one ormore test agents. The test controller can be install...&nbsp;&nbsp;<a href='http://www.cnitblog.com/stomic/archive/2011/05/12/73524.html'>阅读全文</a><img src ="http://www.cnitblog.com/stomic/aggbug/73524.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2011-05-12 11:37 <a href="http://www.cnitblog.com/stomic/archive/2011/05/12/73524.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Load Agent and Load Controller Installation Guide</title><link>http://www.cnitblog.com/stomic/archive/2011/05/11/73520.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Wed, 11 May 2011 09:30:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2011/05/11/73520.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/73520.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2011/05/11/73520.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/73520.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/73520.html</trackback:ping><description><![CDATA[<h4>Team Test Load Controller Installation</h4>
<p>Warning&nbsp;&nbsp; Set up the Controller before setting up any agents.</p>
<p>Note&nbsp;&nbsp; Load controllers cannot be installed on domain controllers.</p>
<p>1. Start setup.exe located in the vs\controller folder.</p>
<p>The Welcome to Setup page appears.</p>
<p>2. Click Next.</p>
<p>The End-User License Agreement and Product Key page appears.</p>
<p>3. Review the End-User License Agreement (EULA) and select I accept the terms
of the license agreement, if appropriate.</p>
<p>4. Enter the product key information and then click Next.</p>
<p>The Destination Folder page appears.</p>
<p>5. Click Browse to select a different destination folder, or click Next to
use the default folder.</p>
<p>The Service Account page appears.</p>
<p>6. Enter the account name and password for the controller service account and
then click Next.</p>
<p>The Ready to Install page appears.</p>
<p>7. Review the installation information and then click Install to
continue.</p>
<p>The Installing Components page appears.</p>
<p>8. Upon successful installation, the Setup Completed Successfully page
appears. Click Finish to complete the Setup program.</p>
<p>During Setup, you are prompted for the controller service account. The
controller service account collects performance counters on other computers
during a load test. Use a domain account that can easily be granted access to
many computers. Grant the controller user rights to monitor performance on all
the systems under test for the built-in performance monitoring capabilities to
work.</p>
<p>Setup creates three local groups:</p>
<p>&#183; TeamTestControllerAdmins</p>
<p>&#183; TeamTestControllerUsers</p>
<p>&#183; TeamTestAgentService</p>
<p>Add users who run tests to <strong>TeamTestControllerUsers</strong>. Add users who
administer the test rig to <strong>TeamTestControllerAdmins</strong>. Agent setup
automatically adds the users who Agent Services run as to
<strong>TeamTestAgentService</strong>.</p>
<p>Note<strong> </strong>The user running the controller setup must be a member of local
<strong>Administrators</strong> group.</p>
<p>The controller runs as a Windows Service on the computers on which it is
installed. To view the properties of the service use Control Panel. In
<strong>Control Panel</strong>, choose <strong>Administrative Tools</strong> and then choose
<strong>Services</strong>. The name of the controller service is the <strong>Visual Studio Team
Test Controller</strong>. The controller services can be started and stopped like
other services in Windows.</p>
<p>The controller and agents can be configured and monitored by using the
Administer Test Controller dialog box, available on the <strong>Test</strong> menu. For
more information, see &#8220;<a  href="http://msdn.microsoft.com/en-us/library/ms182637(VS.80).aspx">How to:
Administer the Rig</a>&#8221; in the product documentation.</p>
<p>By default, the controller uses SQL Express to store load test results. SQL
Express is license limited to store 4GB of data, which is approximately 10 hours
of load test data. If you choose to use another SQL database to store the
results, you can set up the Load Test Results Store after you have installed the
controller. For more information, see &#8220;<a  href="http://msdn.microsoft.com/en-us/library/ms182600.aspx">How to: Configure a
Results Store using SQL</a>&#8221; in the product documentation.</p>
<p>After you have configured your Load Test Results Store, you must indicate to
the controller where the results are to be stored. For more information, see &#8220;<a  href="http://msdn.microsoft.com/en-us/library/ms243400(VS.80).aspx">How to:
Select a <em>Load Test Results Store</em></a>&#8221; in the product documentation.</p>
<h5>Load Controller Firewall Exceptions</h5>
<p>If you are running Windows Firewall, the controller setup adds the following
exceptions to your firewall:</p>
<p><a  href="http://blogs.microsoft.co.il/blogs/shair/WindowsLiveWriter/5d77774c9cbb_F183/LoadControllerFirewallExceptions_2.jpg"><img  src="http://blogs.microsoft.co.il/blogs/shair/WindowsLiveWriter/5d77774c9cbb_F183/LoadControllerFirewallExceptions_thumb.jpg" title="LoadControllerFirewallExceptions" style="border-width: 0px;" alt="LoadControllerFirewallExceptions" width="749" border="0" height="321"></a> </p>
<p>If you are running on Windows XP in a work group, you must turn off Simple
File Sharing. See this KB for info on how to do that: <a  href="http://support.microsoft.com/kb/307874">http://support.microsoft.com/kb/307874</a></p>
<h4>Accessing the Controller</h4>
<p>After the controller is installed, access to the controller is limited to
members of the TeamTestControllerUsers and TeamTestControllerAdmins groups that
were created during Setup, and to the Administrators group. <br>Add appropriate
users and/or groups to these groups to allow them to access the controller.
<br>Members of the TeamTestControllerAdmins group or the Administrators group
can administer the controller by clicking the Test menu, and then choosing
Administer Test Controller in Visual Studio. <br>Members of the
TeamTestControllerAdmins group must also be power users or administrators on the
controller computer.</p>
<h4><a class="" title="Agent" name="Agent"></a>Team Test Load Agent
Installation</h4>
<p>Warning&nbsp;&nbsp;&nbsp; Set up the Controller before setting up any agents.</p>
<p>1. Start setup.exe located in the vs\agent folder.</p>
<p>The Welcome to Setup page appears.</p>
<p>2. Click <strong>Next</strong>.</p>
<p>The End-User License Agreement and Product Key page appears.</p>
<p>3. Review the End-User License Agreement (EULA) and accept the terms of the
license agreement, if appropriate.</p>
<p>4. Enter the product key information and then click <strong>Next</strong>.</p>
<p>The Destination Folder page appears.</p>
<p>5. Click Browse to select a different destination folder, or click
<strong>Next</strong><strong> </strong>to use the default folder.</p>
<p>Note&nbsp;&nbsp; If you are installing the Agent on the same computer as the
Controller, the option to choose a new location is disabled.</p>
<p>The Specify Controller page appears.</p>
<p>6. Enter the computer name of the Team Test Load Controller computer and
click <strong>Next</strong>.</p>
<p>Note&nbsp;&nbsp; You can locate the name of the controller computer by clicking<strong>
</strong>My Computer, right-clicking, choosing Properties and viewing the Computer
Name tab.</p>
<p>The Ready to Install page appears.</p>
<p>7. Review the installation information and then click <strong>Install</strong> to
continue.</p>
<p>The Installing Components page appears.</p>
<p>8. Upon successful installation, the Setup Completed Successfully page
appears. Click <strong>Finish</strong> to complete the setup.</p>
<p>Following this, you will be prompted to restart your computer to complete the
installation.</p>
<p>Note<strong> </strong>The user running the agent setup must be a member of local
Administrators group and a member of the controller&#8217;s Administrators group.<strong>
</strong></p>
<p>During setup, you are prompted for the name of the controller computer that
this agent will be associated with. Agent setup communicates with the controller
to add the agent to the controller.</p>
<p>During setup, you are prompted for the Agent user. This user is automatically
added to <strong>TeamTestAgentService</strong> group on the controller. Only Agent Service
Users who are a member of this group are allowed to communicate with the
controller.</p>
<p>The Agent service is named Visual Studio Team Test Agent. To view the
properties of the service use Control Panel. In <strong>Control Panel</strong>, choose
<strong>Administrative Tools</strong> and then choose <strong>Services</strong>. The agent services
can be started and stopped like other services in Windows. Also the agents can
be administered using the <strong>Administer Test Controller</strong> dialog box,
available on the <strong>Test</strong> menu. For more information, see &#8220;<a  href="http://msdn.microsoft.com/en-us/library/ms182637(VS.80).aspx">How to:
Administer the Rig</a>&#8221; in the product documentation.</p>
<p>Note&nbsp;&nbsp; AgentConfigUtil.exe is a command line utility that can be used to
assign an Agent to a different Controller, or to add an Agent to a Controller if
Agent setup fails to do so.</p>
<h5>Load Agent Firewall Exceptions</h5>
<p>If you are running Windows Firewall, Agent setup added the following
exceptions to your firewall: <br><br><a  href="http://blogs.microsoft.co.il/blogs/shair/WindowsLiveWriter/5d77774c9cbb_F183/LoadAgentFirewallExceptions_2.jpg"><img  src="http://blogs.microsoft.co.il/blogs/shair/WindowsLiveWriter/5d77774c9cbb_F183/LoadAgentFirewallExceptions_thumb.jpg" title="LoadAgentFirewallExceptions" style="border-width: 0px;" alt="LoadAgentFirewallExceptions" width="727" border="0" height="300"></a> </p>
<p>If you are running on Windows XP in a work group, you will also need to turn
off Simple File Sharing.</p>
<h3>Troubleshooting</h3>
<p><strong>Note&nbsp;&nbsp; </strong>To verify the installation, run Visual Studio and
launch the Administer Test Controller dialog box (available from the Test menu),
connect to the controller, and check the status of the agents. <br>Agents should
be in the <strong>Ready</strong> state. <br>If an agent is not in the list of agents,
reinstall the agent or run AgentConfigUtil.exe after verifying that the
controller is installed correctly. <br>If the agent is in the
<strong>Disconnected</strong> state, check that the agent service user account has been
added to the TeamTestAgentService user group on the controller. Also check the
&lt;installdir&gt;\Microsoft Visual Studio 2005 Team Test Load
Agent\LoadTest\agentConfigUtilSetup*.log file for errors. </p>
<p>&#8220;Rig failed to restart for controller &lt;controller computer name&gt;. The
following error was reported Cannot open VSTTController service on computer
&lt;controller computer name&gt;.&#8221;</p>
<p>This error occurs when a user tries to restart the rig from the Administer
Test Controller dialog box, but while this user has been added to the
TeamTestControllerAdmins group, they have not also been added to the Power User
or Administrator group.</p><img src ="http://www.cnitblog.com/stomic/aggbug/73520.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2011-05-11 17:30 <a href="http://www.cnitblog.com/stomic/archive/2011/05/11/73520.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LoadRunner性能测试的几种业务模型设计</title><link>http://www.cnitblog.com/stomic/archive/2009/09/03/61213.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Thu, 03 Sep 2009 02:29:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/09/03/61213.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/61213.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/09/03/61213.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/61213.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/61213.html</trackback:ping><description><![CDATA[<div id=articlebody>
<p>　　一个访问量达到百万级别的门户网站及奥运会订票系统等这中用户数较多的系统，进行<a onclick="javascript:tagshow(event, '%D0%D4%C4%DC%B2%E2%CA%D4');" href="javascript:;" target=_self><u><strong><font color=#0000ff>性能测试</font></strong></u></a>是必须的。要不就和产品演示会上出现的笑话一样，风险投资商提出的问题是这个网站能支持多少用户同时上线，项目经理居然说没有进行这方面的测试。全场哗然。。。。</p>
<p>　　对于性能测试的第一步是怎么去根据业务的实际模型分析出具体的测试场景及性能测试的指标。</p>
<p>　　<strong>一、&nbsp;性能测试业务逻辑理解的一些基本概念</strong></p>
<p>　　1、负载测试和<a onclick="javascript:tagshow(event, '%D1%B9%C1%A6%B2%E2%CA%D4');" href="javascript:;" target=_self><u><strong><font color=#0000ff>压力测试</font></strong></u></a>的区别：负载测试在于确定最终满足系统指标的前提下，系统所能承受的最大负载测试，压力测试的目标则在确定什么条件下系统性能处于失效状态。</p>
<p>　　2、吞吐量（Throughput）：指单位时间内处理的客户段请求数量，直接体现软件系统的性能承载能力。</p>
<p>　　3、并发（Concurrency）：多个同时发生的业务操作。例如100个用户同时点登录21CN邮箱和同时在线人数不一样。比如说21CN通行证用户登录的有1万个可能只有20%的人在看博客，10%的人在看相册，30%的人在查看邮件，10%的人在查看播客，10%的人在看视频点播，10%的人在逛论坛等等</p>
<p>　　但是同时在线人数就是1万，并发用户就是针对每个系统的具体人数。</p>
<p>　　<strong>二、几种常见的业务模型设计</strong></p>
<p>　　1、e家广告系统：</p>
<p>　　（1）具体的业务参数要求：</p>
<p>　　系统要达到4000万日均PV，则需要平台可以处理4000并发/秒。根据选中的服务器的性能，处理能力约为2000个HTTP并发/秒或1000个流媒体并发/秒。假设这4000万PV中有图片的PV占3000万，流媒体的PV占1000万，则需要WEB服务器及流媒体服务器各两台。</p>
<p>　　（2）具体的测试设计方法：</p>
<p>　　（a）平台的处理能力与要达到的日均PV的能力的计算关系为：</p>
<p>　　参数说明：</p>
<p>　　X：表示整个系统的日均PV值，单位为：万PV/天</p>
<p>　　m：平台最大有效并发数（即用来服务于广告物料显示的并发数），单位为：并发/秒，每小时是3600秒，即每个小时处理的并发数为3600m并发，即0.36m万并发/小时。</p>
<p>　　y：非高峰时期的平均并发数与平台最大并发数的比例，0&lt;y&lt;1</p>
<p>　　Y：高峰期（平台达到最大并发数的70%，平台负载超过70%以后，将变得不稳定）小时数,0&lt;Y&lt;24,即高峰期并发数为70%*0.36m</p>
<p>　　那么：</p>
<p>　　日均PV＝高峰期并发数＊高峰期小时数＋非高峰期平均并发数＊（24－高峰期小时数）</p>
<p>　　即：</p>
<p>　　X=0.7*0.36mY+y*0.36m*(24-Y)</p>
<p>　　即最后结论：</p>
<p>　　X=(0.252Y+8.64y-0.36yY)*m</p>
<p>　　根据经验值，Y＝3，y=30%时，m/X=0.33。而m是平台最大有效并发数，即用来服务于广告物料显示的并发数，而对于每次广告物料的显示，客户端还有访问<a onclick="javascript:tagshow(event, '%C6%E4%CB%FC');" href="javascript:;" target=_self><u><strong><font color=#0000ff>其它</font></strong></u></a>资源如JS代码等，假设每一次广告物料的访问会有伴随另外2个资源的访问。</p>
<p>　　那么平台支撑的总的并发数与需要达到的日均PV的比大约为0.33*3=1。</p>
<p>　　（b）实际测试模型设计中结果：</p>
<p>　　对广告链接页面的并发用户数只需要达到N1=0.33*40000000*0.7/24*0.3*3600=356个</p>
<p>　　对于流媒体服务器并发用户数：N2=10000000*0.7/24*0.3*3600/2=135个</p>
<p>　　对于图片服务器并发用户数：N3=30000000*0.7/24*0.3*3600/2=405个</p>
<p>　　2、集团邮箱：</p>
<p>　　（1）具体的业务参数要求：集团邮箱支持支持2000万用户，对性能有要求的操作有邮箱登录，读信，翻页，发邮件（分别是8秒内，2秒内，2秒内，5秒内）。所有的操作均返回HTTP200的状态代码。其中服务器资源分别是登录5台机器（连接PASSPORT），收发邮件5台（不包括POP收发信），其它邮件处理服务器5台，pop/smtp服务器5台。&nbsp;</p>
<p>　　（2）具体的测试设计方法：具体的设计2000万个用户登录时间大概在会在8点到下午18点前操作，而该类业务模型满足80~20原则，比如80%的业务会在20%的时间内处理。则登录的并发用户数设计成多少好呢？&nbsp;VUlogin=20000000*80%/(10*20%*3600*5)&nbsp;其它事物可以以此类推。&nbsp;</p>
<p>　　（3）当然如果业务在要求吞吐量的时候，就要更根据吞吐量来设计性能瓶颈所需要的并发用户数这在我们21CN网站和电子商务网站中经常出现。这里引进一个公式VU=F&nbsp;/R*T(VU并发虚拟用户数,F吞吐量,T性能测试时间,R每个VU的请求数量)举例说明（某网站的吞吐量为90亿KB，每个用户每秒50万kb，运行时间30分钟设计出来的每秒用户数VU=9000000000/(500000*30*30)）</p>
<p>　　（4）如办公系统（业务比较频繁的系统）：每天内的一些典型用户固定可以考虑采用一种更准确的计算并发用户数的的方法。公式引进：C=N*L/T,C1=C+&nbsp;(C是平均并发用户数，N是login&nbsp;session的数量，L是login&nbsp;session的时长，T是考察的时间长度，C1是最高峰值)（*这里的用户是指明确每天都要使用的系统的大概数量来自需求，而这里的用户都是当做一个典型的用户来分析就是登录后会进行正常的流程操作）如21CNEIP每天有320个典型用户访问，系统平均时间为4小时，在一天内用户使用该系统的时间都在8小时内。得出C=320*4/8,C1=C+3&nbsp;(5)针对这几种模式做一些归纳无论那种模型都是来源于需求根据需求的实际模型是最真实的也是最有效的性能测试模型，在没有典型用户的前提下选择2-8原则（在测试环境中要考虑到等价这个概念就是测试环境服务器数量没有实际环境哪么多的时候要折算过来），有典型用户的情况下选择最大并发数的计算方法，在要求有吞吐量的情况下用吞吐量的计算方法（但是吞吐量的数据要采用上一次测试或者经验值中没有突破系统瓶颈的部分数据要不结果不准确，其中每秒事物数取的是平均值）</p>
<p>　　<strong>三、其它值得注意部分</strong></p>
<p>　　1、设置测试场景中并发用户为每隔一段时间增加X个虚拟用户（预热，RAMP&nbsp;UP设置），与同时加载所有的并发用户的测试结果不同，实际的测试中要根据具体业务情况设计。另外实际的<a onclick="javascript:tagshow(event, '%CA%FD%BE%DD%BF%E2');" href="javascript:;" target=_self><u><strong><font color=#0000ff>数据库</font></strong></u></a>记录数和网络环境等都会影响到测试结果。</p>
<p>　　2、建议在实际的测试过程中能多次测试取平均值。</p>
<p>　　3、性能测试的&#8221;拐点论&#8221;:产生拐点的情况是性能测试产生某种瓶颈，主要原因是某种资源达到了极限。此时表现为随着压力的增大，系统性能出现急剧下降。</p>
<p>　　4、性能测试的系统能力验证:&nbsp;（a）是系统稳定性的一个基本要求，通常表现为系统在要求的平均并发用户下服务器的CPU平均使用率不高于75%，内存的使用率不高于75%。（b）系统在要求的并发用户数达到峰值情况下服务器的CPU平均使用率不高于95%，内存的使用率不高于90%。（c）系统能在高于实际系统运行压力1倍的情况下，稳定的运行72小时。</p>
<p>　　5、为分清各个不同事物的响应时间请务必在多事物的脚本中添加事物以便区分，请在要用到多个帐户或者多个用户的迭代或者循环操作的时候请务必进行参数化（很多系统都限制了同一帐户在多长时间的操作，或者防止数据冲突）。<br></p>
<p>邮箱：<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#105;&#100;&#101;&#110;&#121;&#50;&#48;&#48;&#57;&#64;&#103;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">sideny2009@gmail.com</a></p>
<p>MSN：<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#120;&#109;&#105;&#110;&#103;&#50;&#48;&#49;&#48;&#64;&#104;&#111;&#116;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">kxming2010@hotmail.com</a></p>
</div>
<img src ="http://www.cnitblog.com/stomic/aggbug/61213.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-09-03 10:29 <a href="http://www.cnitblog.com/stomic/archive/2009/09/03/61213.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存泄漏的有关知识</title><link>http://www.cnitblog.com/stomic/archive/2009/08/21/60908.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Fri, 21 Aug 2009 06:22:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/08/21/60908.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/60908.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/08/21/60908.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/60908.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/60908.html</trackback:ping><description><![CDATA[<p><font color=#000000 size=4>1、概念<br>简单的说就是你申请了一块内存空间，使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长，占用内存越多，最终用尽全部内存，整个系统崩溃。由程序申请的一块内存，且没有任何一个指针指向它，那么这块内存就泄露了。</font></p>
<p><br><font color=#000000 size=4>2、泄漏的例子<br>举几个例子&nbsp; &nbsp;<br>&nbsp;&nbsp;void&nbsp; &nbsp;fun0()&nbsp; &nbsp;<br>&nbsp;&nbsp;{&nbsp; &nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;char&nbsp; &nbsp;*p=new&nbsp; &nbsp;char[100];&nbsp; &nbsp;<br>&nbsp;&nbsp;}&nbsp; &nbsp;<br>&nbsp;&nbsp;执行完上面的函数就发生了泄露&nbsp; &nbsp;<br>&nbsp;&nbsp;指针p是局部变量，函数执行完后，指针p被销毁，造成&nbsp; &nbsp;new&nbsp; &nbsp;char[100]的内存没有指针指向它&nbsp; &nbsp;<br>&nbsp;&nbsp;，也就无法再使用，造成内存泄漏。&nbsp;&nbsp;<br>&nbsp;&nbsp;void&nbsp; &nbsp;fun1()&nbsp; &nbsp;<br>&nbsp;&nbsp;{&nbsp; &nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;char&nbsp; &nbsp;*p=new&nbsp; &nbsp;char[100];&nbsp; &nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;p=new&nbsp; &nbsp;char[100];&nbsp; &nbsp;<br>&nbsp;&nbsp;}&nbsp; &nbsp;<br>&nbsp;&nbsp;这也泄露了&nbsp; &nbsp;<br>&nbsp; &nbsp;<br>&nbsp;&nbsp;void&nbsp; &nbsp;fun2()&nbsp; &nbsp;<br>&nbsp;&nbsp;{&nbsp; &nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;new&nbsp; &nbsp;char[100];&nbsp; &nbsp;<br>&nbsp;&nbsp;}&nbsp; &nbsp;<br>&nbsp;&nbsp;这东西肯定泄露完了&nbsp; &nbsp;<br>&nbsp; &nbsp;<br>&nbsp;&nbsp;void&nbsp; &nbsp;fun3(char&nbsp; &nbsp;*a)&nbsp; &nbsp;<br>&nbsp;&nbsp;{&nbsp; &nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;char&nbsp; &nbsp;*p=new&nbsp; &nbsp;char[100];&nbsp; &nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;char&nbsp; &nbsp;*b=p;&nbsp; &nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;p=a;&nbsp; &nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;a=b;&nbsp; &nbsp;<br>&nbsp;&nbsp;}&nbsp; &nbsp;<br>&nbsp;&nbsp;可能有泄露，赶紧去加内存条。</font></p>
<p><br><font color=#000000 size=4>3、泄漏的分类<br>以发生的方式来分类，内存泄漏可以分为4类：<br>（1）常发性内存泄漏。发生内存泄漏的代码会被多次执行到，每次被执行的时候都会导致一块内存泄漏。<br>（2）偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境，偶发性的也许就变成了常发性的。所以<a onclick="javascript:tagshow(event, '%B2%E2%CA%D4');" href="javascript:;" target=_self><u><strong><font color=#800080>测试</font></strong></u></a>环境和测试方法对检测内存泄漏至关重要。<br>（3）一次性内存泄漏。发生内存泄漏的代码只会被执行一次，或者由于算法上的缺陷，导致总会有一块仅且一块内存发生泄漏。比如，在类的构造函数中分配内存，在析构函数中却没有释放该内存，所以内存泄漏只会发生一次。<br>（4）隐式内存泄漏。程序在运行过程中不停的分配内存，但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏，因为最终程序释放了所有申请的内存。但是对于一个服务器程序，需要运行几天，几周甚至几个月，不及时释放内存也可能导致最终耗尽系统的所有内存。所以，我们称这类内存泄漏为隐式内存泄漏。<br>从用户使用程序的角度来看，内存泄漏本身不会产生什么危害，作为一般的用户，根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积，这会最终消耗尽系统所有的内存。从这个角度来说，一次性内存泄漏并没有什么危害，因为它不会堆积，而隐式内存泄漏危害性则非常大，因为较之于常发性和偶发性内存泄漏它更难被检测到。</font></p>
<p><br><font color=#000000 size=4>4、内存泄漏的表现<br>内存泄漏或者是说，资源耗尽后，系统会表现出什么现象哪？<br>cpu资源耗尽：估计是机器没有反应了，键盘，鼠标，以及网络等等。这个在windows上经常看见，特别是中了毒。<br>进程id耗尽：没法创建新的进程了，串口或者telnet都没法创建了。<br>硬盘耗尽： 机器要死了，交换内存没法用，<a onclick="javascript:tagshow(event, '%C8%D5%D6%BE');" href="javascript:;" target=_self><u><strong><font color=#800080>日志</font></strong></u></a>也没法用了，死是很正常的。<br>内存泄漏或者内存耗尽：新的连接无法创建，free的内存比较少。发生内存泄漏的程序很多，但是要想产生一定的后果，就需要这个进程是无限循环的，是个服务进程。当然，内核也是无限循环的，所以，如果内核发生了内存泄漏，情况就更加不妙。内存泄漏是一种很难定位和跟踪的错误，目前还没看到有什么好用的工具（当然，用户空间有一些工具，有静态分析的，也会动态分析的，但是找内核的内存泄漏，没有好的开源工具）<br>内存泄漏和对象的引用计数有很大的关系，再加上c/c++都没有自动的垃圾回收机制，如果没有手动释放内存，问题就会出现。如果要避免这个问题，还是要从代码上入手，良好的编码习惯和规范，是避免错误的不二法门。</font></p>
<p><br><font color=#000000 size=4>5.内存泄漏的检测<br>另外网上还有很多针对<a onclick="javascript:tagshow(event, 'java');" href="javascript:;" target=_self><u><strong><font color=#800080>java</font></strong></u></a>和c＋＋等的内存泄漏的<a onclick="javascript:tagshow(event, '%CE%C4%D5%C2');" href="javascript:;" target=_self><u><strong><font color=#800080>文章</font></strong></u></a><br>Java内存泄漏：</font><a href="http://www.blogjava.net/galaxyp/archive/2006/04/28/43724.html" target=_blank><font color=#000000 size=4><u>http://www.blogjava.net/galaxyp/archive/2006/04/28/43724.html</u></font></a><br><font color=#000000 size=4>VC6.0内存泄漏检测：</font><a href="http://leoman95.spaces.live.com/" target=_blank><font color=#000000 size=4><u>http://leoman95.spaces.live.com/</u></font></a><font color=#000000 size=4>... e8fa434b1!131.entry<br>LR中：如果Process\Private Bytes计数器和Process\Working Set计数器的值持续升高，同时Memory\Available bytes计数器的值却持续降低的话，说明很有可能是存在内存泄漏</font></p>
<img src ="http://www.cnitblog.com/stomic/aggbug/60908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-08-21 14:22 <a href="http://www.cnitblog.com/stomic/archive/2009/08/21/60908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何使用LoadRunner来监控MySql数据库的性能</title><link>http://www.cnitblog.com/stomic/archive/2009/08/06/60594.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Thu, 06 Aug 2009 08:44:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/08/06/60594.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/60594.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/08/06/60594.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/60594.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/60594.html</trackback:ping><description><![CDATA[<p>一、利用SiteScope工具来监控</p>
<p>&nbsp;&nbsp;&nbsp;在<a href="http://www.51testing.com/javascrīpt:;" target=_self ōnclick="javascrīpt:tagshow(event, 'LoadRunner');"><u><strong><a onclick="javascript:tagshow(event, 'LoadRunner');" href="javascript:;" target=_self><u><strong><font color=#800080>LoadRunner</font></strong></u></a></strong></u></a>中没有提供直接监控<a href="http://www.51testing.com/javascrīpt:;" target=_self ōnclick="javascrīpt:tagshow(event, 'MySQL');"><u><strong><a onclick="javascript:tagshow(event, 'MySQL');" href="javascript:;" target=_self><u><strong><font color=#800080>MySQL</font></strong></u></a></strong></u></a>的方法，但是在实际<a href="http://www.51testing.com/javascrīpt:;" target=_self ōnclick="javascrīpt:tagshow(event, '%B9%A4%D7%F7');"><u><strong><a onclick="javascript:tagshow(event, '%B9%A4%D7%F7');" href="javascript:;" target=_self><u><strong><font color=#800080>工作</font></strong></u></a></strong></u></a>中需要我们对mysql数据库服务器进行监控，我们可以利用sitescope监控然后在lr中显示SiteScope监控的结果，达到间接监控mysql的目的。</p>
<p>&nbsp;&nbsp; 备注：<font size=2>Mercyry<strong>SiteScope</strong>介绍：它是一款无代理监测解决方案，可确保分布式IT基础架构——如服务器、<a href="http://www.51testing.com/javascrīpt:;" target=_self ōnclick="javascrīpt:tagshow(event, '%B2%D9%D7%F7%CF%B5%CD%B3');"><u><strong><a onclick="javascript:tagshow(event, '%B2%D9%D7%F7%CF%B5%CD%B3');" href="javascript:;" target=_self><u><strong><font color=#800080>操作系统</font></strong></u></a></strong></u></a>、网络设备、网络服务、应用和应用组件的可用性和性能。这款主动的、基于<a href="http://www.51testing.com/javascrīpt:;" target=_self ōnclick="javascrīpt:tagshow(event, 'Web');"><u><strong><a onclick="javascript:tagshow(event, 'Web');" href="javascript:;" target=_self><u><strong><font color=#800080>Web</font></strong></u></a></strong></u></a>界面的基础架构监测解决方案是非常简洁的，而且完全根据客户度身定制，无需在您的上线系统中增加额外的代理。<br><strong>SiteScope</strong>为上线系统提供24&#215;7的监控服务，为维护工程师及时发现问题提供帮助，确保系统架构内一切组建的正常运作。<strong>SiteScope</strong>在大量增加检测周期的同时也降低了维护人员的工作成本 。<br><strong>SiteScope</strong>能够监控<strong>UNIX服务器资源、windows服务器资源、weblogic应用服务器、IIS应用服务器、<a onclick="javascript:tagshow(event, 'Oracle');" href="javascript:;" target=_self><u><strong><font color=#800080>Oracle</font></strong></u></a>数据库、SQLServer数据库、F5、URL地址、Ping、内存、CPU、磁盘空间、服务</strong>等等系统架构内各种组建的运行状况；监控器按照指定频率对目标进行检测，一旦发现异常会及时向管理员发送意外事件的报警，警报可以通过声音提醒、email、短信等方式发送；另外，SiteScope还可以生成监测活动的汇总报告，该对象从<a href="http://www.51testing.com/javascrīpt:;" target=_self ōnclick="javascrīpt:tagshow(event, '%C8%D5%D6%BE');"><u><strong><a onclick="javascript:tagshow(event, '%C8%D5%D6%BE');" href="javascript:;" target=_self><u><strong><font color=#800080>日志</font></strong></u></a></strong></u></a>文件中读取历史信息，接着总结、筛选信息，并生成图表格式的报告。</font></p>
<p><font size=2>&nbsp;&nbsp; SiteScope利用<strong>Database Query monitor监控指定的<a href="http://www.51testing.com/javascrīpt:;" target=_self ōnclick="javascrīpt:tagshow(event, '%CA%FD%BE%DD%BF%E2');"><u><strong><a onclick="javascript:tagshow(event, '%CA%FD%BE%DD%BF%E2');" href="javascript:;" target=_self><u><strong><font color=#800080>数据库</font></strong></u></a></strong></u></a>，通过SiteScope监控器的SHOW STATUS</strong>命令，获得相应数据，命令如下:</font></p>
<p><font size=2>&nbsp;&nbsp;<em>show status where variable_name like &#8217;innodb_buffer_pool_pages_total&#8217;</em></font></p>
<p><font size=2><em>&nbsp;</em>为了确保监控请确认LoadRunner and SiteScope之间的端口, SiteScope和MySQL必须打开<strong>TCP 8888</strong>和<strong>TCP 3306</strong>&nbsp;.&nbsp;还有SiteScope要监控必须要确保有JDBC的安装。&nbsp;</p>
<p><em>以下为监控前需要注意的地方：</em></p>
<ul><em>1. SiteScope to be deployed.<br>2. Sufficient license points for Database Query monitor.<br>3. TCP 8888 (default) opened two-way for LoadRunner to SiteScope.<br>4. TCP 3306 (default) opened two-way for SiteScope to MySQL.<br>5. Monitoring privileges for SiteScope to monitor MySQL.<br>6. JDBC driver to be installed on SiteScope.<br>7. Have knowledge of the counter you want to monitor.</em></ul>
    </font>
    <p><font size=2><em>转自SiteScope帮助：</em></font></p>
    <font size=2><em>
    <h2>Monitoring mySQL Databases</h2>
    <p>Monitoring a<a href="http://127.0.0.1:8567/do/z_aZ/tttLXq9lDLxjX/"><font color=#000066><u>MySQL</u></font></a>database requires the use of a JDBC driver. To enable SiteScope to monitor a MySQL database:</p>
    <ol>
        <li>Download the JDBC driver from<a href="http://127.0.0.1:8567/do/z__Z/tttLXE9lDLe0X/M0tYD0vM3/api-jdbc.html"><font color=#000066><u>http://www.mysql.com/downloads/api-jdbc.html</u></font></a>
        <li>Uncompress the distribution file
        <li>Among all the other files, you should find a file with a .jar extension.
        <li>Copy the .jar file into the<tt><font face=新宋体>&lt;SiteScope install path&gt;/SiteScope/java/lib/ext</font></tt>directory
        <li>Stop and restart SiteScope
        <li>Now, use your browser to add a Database Query Monitor within SiteScope.
        <p>The Database Connection URL format for the MySQL JDBC driver is:
        <p><tt><font face=新宋体>jdbc:mysql://&lt;database hostname&gt;[:&lt;tcp port&gt;]/&lt;database&gt;</font></tt></p>
        For example to connect to the MySQL database "aBigDatabase" on a machine using the standard MySQL port number<tt><font face=新宋体>3306</font></tt>you would use:
        <p><tt><font face=新宋体>jdbc:mysql://206.168.191.19/aBigDatabase</font></tt></p>
        <p>If you are using a different port to connect to the database then you should include that port number as part of the IP address.</p>
        <p>The specification for the MySQL JDBC driver is:<tt><font face=新宋体>org.gjt.mm.mysql.Driver</font></tt>
        <p>Enter this string into the Database Driver text box under the<a href="http://127.0.0.1:8567/do/Q__Z/9xzR9aLbiMLY0fvTLgfb:IIJJ/9AaN9x0ZN/M0x3/DatabaseMon.htm#advanced"><font color=#000066><u>Advanced Options</u></font></a>section of the Add Database Query Monitor form.</p>
        </li>
    </ol>
    <p>二、通过编写脚本来进行监控</p>
    <p>// mysql_dll.cpp : Defines the entry point for the DLL application.</p>
    <p>#include "stdafx.h"<br>#include "stdlib.h"</p>
    <p>MYSQL *conn=NULL;<br>MYSQL_RES *p_res_ptr=NULL;<br>MYSQL_ROW sqlrows;</p>
    <p><br>BOOL APIENTRY DllMain( HANDLE hModule,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD&nbsp; ul_reason_for_call,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPVOID lpReserved<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br>{<br>&nbsp;&nbsp;&nbsp; return TRUE;<br>}</p>
    <p>extern "C" int _declspec(dllexport) init_mysql_connection(char *str_server,char *str_username,char *str_pwd,char *str_Table)<br>{<br>&nbsp;conn=mysql_init(NULL);</p>
    <p>&nbsp;&nbsp;&nbsp; if(!conn)<br>&nbsp;{<br>&nbsp;&nbsp;printf("\nFailed to initate MySQL connection");<br>&nbsp;&nbsp;return 1;<br>&nbsp;&nbsp;exit(0);<br>&nbsp;}<br>&nbsp;&nbsp;&nbsp; else<br>&nbsp;{<br>&nbsp;&nbsp;printf("\nSuccess to initate MySQL connection");<br>&nbsp;&nbsp;if (!mysql_real_connect(conn,str_server,str_username,str_pwd,str_Table,0,NULL,0))<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;printf( "Failed to connect to MySQL: Error: %s\n", mysql_error(conn));<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;else<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;printf("\nLogged on to %s sucessfully",str_server);<br>&nbsp;&nbsp;&nbsp;return 0;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;return 0;<br>&nbsp;}<br>}</p>
    <p>extern "C" int _declspec(dllexport) close_mysql_connection()<br>{<br>&nbsp;if(conn=NULL)<br>&nbsp;{<br>&nbsp;&nbsp;printf("\nConnection is Null");<br>&nbsp;&nbsp;return 1;<br>&nbsp;&nbsp;exit(0);<br>&nbsp;}<br>&nbsp;else<br>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp; mysql_free_result(p_res_ptr);<br>&nbsp;&nbsp;printf("\nClose connection");<br>&nbsp;&nbsp;mysql_close(conn);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return 0;<br>&nbsp;}<br>}</p>
    <p>//"show status like \'qcache%\'"</p>
    <p>extern "C" int _declspec(dllexport) get_mysql_table_query(char *str_query)<br>{<br>&nbsp;int res=0;<br>&nbsp;res=mysql_query(conn,str_query);<br>&nbsp;if(res)<br>&nbsp;{<br>&nbsp;&nbsp;printf("Failed to mysql query: Error: %s\n", mysql_error(conn));<br>&nbsp;&nbsp;return 1;<br>&nbsp;}<br>&nbsp;else<br>&nbsp;{<br>&nbsp;&nbsp;printf("\nSucess in Mysql Query");<br>&nbsp;&nbsp;return 0;</p>
    <p>&nbsp;}</p>
    <p>}</p>
    <p>&nbsp;</p>
    <p>extern "C" int _declspec(dllexport) get_mysql_query_data(char *str_query,char *str_data)<br>{<br>&nbsp;&nbsp;&nbsp; unsigned long u1_numrow=0;<br>&nbsp;&nbsp;&nbsp; unsigned int i_index = 0;<br>&nbsp;p_res_ptr=mysql_use_result(conn);</p>
    <p>&nbsp;if(p_res_ptr){<br>&nbsp;<br>&nbsp;&nbsp;while((sqlrows=mysql_fetch_row(p_res_ptr))){<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;if(*sqlrows[0]=*str_query)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;strcpy(str_data,sqlrows[1]);<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>&nbsp;}</p>
    <p>&nbsp;return NULL;</p>
    <p>}</p>
    <p>&nbsp;</p>
    <p>lr 9.1中代码：</p>
    <div twffan="done">Action()<br>{</div>
    <div twffan="done"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i=0;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double x;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *str_data;<br>&nbsp;</div>
    <div twffan="done">&nbsp;</div>
    <div twffan="done">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str_data=(char *)malloc(20*sizeof(char));</div>
    <div twffan="done">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lr_load_dll("D:\\vc\\mysql_dll\\Debug\\mysql_dll.dll");&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i= init_mysql_connection("localhost","root","123456","mysql");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lr_output_message("%d",i);<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(;;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get_mysql_query_data("Qcache_hits",str_data);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i=get_mysql_table_query("show status like \'qcache%\'");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lr_output_message("%d",i);</div>
    <div twffan="done">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = atof(str_data);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lr_user_data_point("hits",x);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lr_think_time(5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</div>
    <div twffan="done">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lr_output_message("%d",x);<br>&nbsp;&nbsp;&nbsp;&nbsp; close_mysql_connection();</div>
    <div twffan="done">&nbsp;return 0;<br>}</div>
    </em></font>
<img src ="http://www.cnitblog.com/stomic/aggbug/60594.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-08-06 16:44 <a href="http://www.cnitblog.com/stomic/archive/2009/08/06/60594.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Does LoadRunner transaction response time include the rendering time of the browser?</title><link>http://www.cnitblog.com/stomic/archive/2009/06/19/59502.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Fri, 19 Jun 2009 06:34:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/06/19/59502.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/59502.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/06/19/59502.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/59502.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/59502.html</trackback:ping><description><![CDATA[<p>The answer is &#8220;No&#8221;! The reason is very simple, LoadRunner is not designed for client-side activities (remember, it&#8217;s all about network traffic!). We will illustrate using Web (HTTP/HTML) protocol.</p>
<p>Keep in mind that when we mention rendering time, it means the time taken for the display of the web components, Javascript or applet to load in the browser (or anything that is considered client-activity, loading in the browser) that is being activated after the HTML page is being received.</p>
<p>When we replay the scripts in LoadRunner, network traffic are being generated by the APIs (functions) and are expected to receive before the subsequent step can be executed. All this are taken place in memory and what LoadRunner does is to generate the traffic and receive the responses in memory. No user interface (UI) is launched in the process of replay for the purpose of rendering the pages received. Having no UI launched, rendering is omitted.</p>
<p>In a real user environment, the entire time for response in user perspective includes the request sending time, request processed time, response time and the browser loading (rendering time). However, in the context of LoadRunner, UI is not part of this entire request and response cycle.</p>
<p>Keep in mind that the transmission of the data is still pure text (or binary) and that needs to be rendered by the browser to be displayed properly. That&#8217;s considering the Javascript and any applets that needs to be loaded which is greatly dependent on the browser (eg. IE, Modzilla)and your machine specifications.</p>
<p>Even for Web Page Diagnostics, rendering time is not included as part of the transaction response time. It only allows the drill-down of time taken to download web components and not the time taken to render the component for display. In summary, it&#8217;s still at the network level.</p>
<p>If you are looking for an end-to-end response time testing that includes the rendering of the UI, you should consider using the GUI vuser protocol. The protocol utilizes another (famous) HP testing product, Quick Test Professional (QTP) as the recording mechanism, and replays the QTP scripts in the Load Generators as GUI vusers. For official information on the GUI vuser protocol, you can refer to the HP LoadRunner (v9.0) Controller User Guide, Chapter 14, &#8220;Using Functional Testing Scripts in LoadRunner&#8221;.</p>
<img src ="http://www.cnitblog.com/stomic/aggbug/59502.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-06-19 14:34 <a href="http://www.cnitblog.com/stomic/archive/2009/06/19/59502.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LoadRunner中Web_submit_form和Web_submit_data的区别详细解释</title><link>http://www.cnitblog.com/stomic/archive/2009/03/27/55785.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Thu, 26 Mar 2009 16:00:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/27/55785.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55785.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/27/55785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55785.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55785.html</trackback:ping><description><![CDATA[<p>在LoadRunner中有两个常用函数:Web_submit_form和Web_submit_data，在群里有人问这两个函数有什么区别。为什么会有两个不同却功能相似的函数。区别在哪里。
<p>首先，从工具的角度来说，厂商推荐使用Web_submit_form函数，因为这个函数看起来更易用，需要关注的东西较少。但是，从个人的角度来说，我推荐使用Web_submit_data函数。因为这个函数提供更多技术细节。在测试的过程中可控性更高。下面我就详细解释一下两个函数的工作机制：
<p>首先看一下下面这段HTML代码
<p><strong>&lt;Form Action=login.asp Method=</strong><strong>&#8220;</strong><strong>POST</strong><strong>&#8221;</strong><strong>&gt; </strong>
<p><strong>&lt;input name=user value=</strong><strong>&#8220;&#8221;</strong><strong>&gt; </strong>
<p><strong>&lt;input name=password value=</strong><strong>&#8220;&#8221;</strong><strong>&gt; </strong>
<p><strong>&lt;input type=hidden name=sessionID value=15379&gt; </strong>
<p><strong>&lt;/Form&gt; </strong>
<p>在录制的过程中，当打开这个页面的时候，这个页面会放在LR的Cache中，之后当我们输入了用户名、口令之后，点了一下提交。Browser会向LR Record Proxy发送一个提交请求，提交内容应该是这样的：
<p><strong>POST login.asp HTTP/1.1 </strong>
<p><strong>user=steve password=buba </strong>
<p><strong>sessionID=15379</strong>
<p>这时候，LR会自动比较提交的内容和Cache的内容，首先它会比较提交的数据项和Cache中的数据项是否一致。页面中有三个输入域user、password、sessionID，而提交的内容也有这三项数据，所以它认为提交数据使用了Cache中的页面，之后它会继续比较具体数据的值。它会发现sessionID的值和Cache中的值是一样的。但是user和password的值不一样。
<p>这时候，Web_submit_form和Web_submit_data的区别就出现了：
<p><strong>web_submit_form</strong><strong>(&#8221;start", </strong>
<p><strong>ITEMDATA, </strong>
<p><strong>"name=user", "value=steve", ENDITEM, </strong>
<p><strong>"name=password", "value=bean", ENDITEM, </strong>
<p><strong>LAST);</strong>
<p>&nbsp;
<p><strong>web_submit_data</strong><strong>(&#8221;start", </strong>
<p><strong></strong><strong>&#8220;</strong><strong>Action=login.asp</strong><strong>&#8221;</strong><strong>, </strong>
<p><strong></strong><strong>&#8220;</strong><strong>Method=POST</strong><strong>&#8221;</strong><strong> </strong>
<p><strong>ITEMDATA, </strong>
<p><strong>"name=user", "value=steve", ENDITEM, </strong>
<p><strong>"name=password", "value=bean", ENDITEM, </strong>
<p><strong>"name=sessionID", "value=15379", ENDITEM, </strong>
<p><strong>LAST); </strong>
<p>可以看到，Web_submit_form只提供了和Cache中有差别的数据，其余的数据会自动从Cache中取。而Web_submit_data则提供了所有的数据，不管Cache存在不存在Web_submit_data都是可以工作的。
<p>所以厂商会推荐使用Web_submit_form，因为它看起来更易用，甚至关联都不需要作，就能直接回放。但是这种情况只能对于简单系统适用。对于一些银行或者移动的复杂系统来说，有时侯会对Cache作特殊操作，Web_submit_form有时侯就会报一些莫名其妙的错出来。而Web_submit_data则跟Cache内容无关。稳定性和可控性都要比Web_submit_form要高很多。所以个人推荐尽量使用Web_submit_data函数。 </p>
<img src ="http://www.cnitblog.com/stomic/aggbug/55785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-27 00:00 <a href="http://www.cnitblog.com/stomic/archive/2009/03/27/55785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入理解Loadrunner中的Browser Emulation</title><link>http://www.cnitblog.com/stomic/archive/2009/03/24/55721.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Tue, 24 Mar 2009 13:54:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/24/55721.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55721.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/24/55721.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55721.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55721.html</trackback:ping><description><![CDATA[<p><strong>一：基本介绍</strong></p>
<p>在Loadrunner的使用中，对于Run-time Settings下的browser emulation设置是比较容易让人产生困惑的地方。下面我们结合sniffer来具体看看每个选项的用途，以及对测试的影响。 </p>
<p><a  href="http://www.blogjava.net/images/blogjava_net/tacy/WindowsLiveWriter/LoadrunnerBrowserEmulation_461/clip_image002_2.gif"><img  src="http://www.blogjava.net/images/blogjava_net/tacy/WindowsLiveWriter/LoadrunnerBrowserEmulation_461/clip_image002_thumb.gif" style="border: 0px none ;" alt="clip_image002" width="573" border="0" height="248"></a> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Browser Emulation 图</p>
<p><strong>二：案例和工具</strong></p>
<p><strong>1. </strong><strong>测试案例：</strong> </p>
<p>打开网站首页两次，对比不同Browser Emulation设置下loadrunner的行为，脚本如下。 </p>
<div class="csharpcode-wrapper">
<pre class="csharpcode">Action()<br>{<br>    web_url(<span class="str">"www.primeton.com"</span>, <br>        <span class="str">"URL=http://www.primeton.com/"</span>, <br>        <span class="str">"Resource=0"</span>, <br>        <span class="str">"RecContentType=text/html"</span>, <br>        <span class="str">"Referer="</span>, <br>        <span class="str">"Snapshot=t2.inf"</span>, <br>        <span class="str">"Mode=HTML"</span>, <br>        LAST);<br><br>    web_url(<span class="str">"www.primeton.com"</span>, <br>        <span class="str">"URL=http://www.primeton.com/"</span>, <br>        <span class="str">"Resource=0"</span>, <br>        <span class="str">"RecContentType=text/html"</span>, <br>        <span class="str">"Referer="</span>, <br>        <span class="str">"Snapshot=t2.inf"</span>, <br>        <span class="str">"Mode=HTML"</span>, <br>        LAST);<br><br>    <span class="kwrd">return</span> 0;<br>}<br></pre>
</div>
<p>
</p>
<p><strong>2. </strong><strong>sniffer</strong><strong>工具</strong>
</p>
<p>开源工具：Wireshark(前身是ethereal)（www.wireshark.org）
</p>
<p><strong>三：测试过程</strong></p>
<p>为了方便描述，我们约定用：
</p>
<p><em>A</em><em>代表Simulate browser cache</em>
</p>
<p><em>B</em><em>代表Cache URLs requiring content(HTMLs)</em>
</p>
<p><em>C</em><em>代表Check for newer versions of stored pages every visit to the page</em>
</p>
<p><em>D</em><em>代表Download non-HTML resources</em>
</p>
<p><em>E</em><em>代表Simulate a new user on each iteratioin</em>
</p>
<p><em>F</em><em>代表Clear cache on each iteration</em>
</p>
<p>首先设置Run Logic中的iteration为2。让Action运行两次，看看循环运行脚本两次，数据包和连接数的变化。
</p>
<p><strong>1. </strong><strong>去掉所有选项</strong>
</p>
<p>结果：共获取数据包95个，建立连接1个（红色标识），断开连接1个（蓝色标识）
</p>
<div class="csharpcode-wrapper">
<div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4; max-height: 200px;">
<pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4;">No.     Time        Source            Destination       Protocol Info<br>      <font color="#ff0000">1 0.000000    192.168.1.61      203.81.29.137     TCP      13835 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br></font>      2 0.036053    203.81.29.137     192.168.1.61      TCP      http &gt; 13835 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br>     <font color="#0000ff">92 1.415887    192.168.1.61      203.81.29.137     TCP      13835 &gt; http [FIN, ACK] Seq=817 Ack=71762 Win=257760 Len=0<br></font>     94 1.449960    203.81.29.137     192.168.1.61      TCP      http &gt; 13835 [FIN, ACK] Seq=71762 Ack=818 Win=16464 Len=0<br></pre>
</div>
</div>
<p>
</p>
<p>在这种情况下，数据包非常少（没有选择下载资源文件入css,js,gif等），而且你可以看到，打开4次首页，只建立了一个tcp连接。
</p>
<p>这时，你即使选择A，发现数据包的数量量页没有变化，因为cache主要还是针对资源文件
</p>
<p><strong>2. </strong><strong>选择E(F)</strong>
</p>
<p>结果：共获取数据包102个，建立连接2个（红色标识），断开连接2个（蓝色标识）</p>
<div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4; max-height: 200px;">
<pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4;">No.     Time        Source            Destination       Protocol Info<br>      <font color="#ff0000">1 0.000000    192.168.1.61      203.81.29.137     TCP      13886 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br></font>      2 0.037013    203.81.29.137     192.168.1.61      TCP      http &gt; 13886 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br><font color="#0000ff">     48 0.618117    192.168.1.61      203.81.29.137     TCP      13886 &gt; http [FIN, ACK] Seq=409 Ack=35882 Win=257760 Len=0<br></font><font color="#ff0000">     49 0.644106    192.168.1.61      203.81.29.137     TCP      13887 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br></font>     51 0.651919    203.81.29.137     192.168.1.61      TCP      http &gt; 13886 [FIN, ACK] Seq=35882 Ack=410 Win=16872 Len=0<br>     53 0.676377    203.81.29.137     192.168.1.61      TCP      http &gt; 13887 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br><font color="#0000ff">     99 1.310379    192.168.1.61      203.81.29.137     TCP      13887 &gt; http [FIN, ACK] Seq=409 Ack=35882 Win=257760 Len=0</font><br>101 1.347949    203.81.29.137     192.168.1.61      TCP      http &gt; 13887 [FIN, ACK] Seq=35882 Ack=410 Win=16872 Len=0<br></pre>
</div>
<p>在这种情况下，数据包非常少（没有选择下载资源文件入css,js,gif等），对比第一种情况，你会发现它建立了两个连接，这就是E的作用，它对于每次迭代都当成一个新的用户，需要重新建立连接。
</p>
<p><strong>3. </strong><strong>选择DE(F)</strong>
</p>
<p>结果：共获取数据包1782个，建立连接6个（红色标识），断开连接6个（蓝色标识）</p>
<div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4; max-height: 200px;">
<pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4;">No.     Time        Source            Destination       Protocol Info<br>      <font color="#ff0000">1 0.000000    192.168.1.61      203.81.29.137     TCP      14016 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br></font>      2 0.037911    203.81.29.137     192.168.1.61      TCP      http &gt; 14016 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br><font color="#ff0000">      6 0.107432    192.168.1.61      203.81.29.137     TCP      14017 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2</font><br>      9 0.141816    203.81.29.137     192.168.1.61      TCP      http &gt; 14017 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br><font color="#0000ff">    426 3.334889    192.168.1.61      203.81.29.137     TCP      14017 &gt; http [FIN, ACK] Seq=1852 Ack=150284 Win=257484 Len=0<br></font>    428 3.372253    203.81.29.137     192.168.1.61      TCP      http &gt; 14017 [FIN, ACK] Seq=150284 Ack=1853 Win=16998 Len=0<br><font color="#ff0000">    448 4.395488    192.168.1.61      203.81.29.137     TCP      14020 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br></font>    457 4.439604    203.81.29.137     192.168.1.61      TCP      http &gt; 14020 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br><font color="#0000ff">    859 7.593610    192.168.1.61      203.81.29.137     TCP      14016 &gt; http [FIN, ACK] Seq=2849 Ack=377404 Win=257484 Len=0</font><br>    870 7.659680    203.81.29.137     192.168.1.61      TCP      http &gt; 14016 [FIN, ACK] Seq=377404 Ack=2850 Win=15935 Len=0<br><font color="#0000ff">    888 8.511308    192.168.1.61      203.81.29.137     TCP      14020 &gt; http [FIN, ACK] Seq=1602 Ack=208150 Win=257760 Len=0<br></font>    890 8.549451    203.81.29.137     192.168.1.61      TCP      http &gt; 14020 [FIN, ACK] Seq=208150 Ack=1603 Win=17280 Len=0<br><font color="#ff0000">    892 8.566246    192.168.1.61      203.81.29.137     TCP      14022 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2</font><br>    893 8.601893    203.81.29.137     192.168.1.61      TCP      http &gt; 14022 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br><font color="#ff0000">    899 8.702628    192.168.1.61      203.81.29.137     TCP      14023 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2</font><br>    904 8.741807    203.81.29.137     192.168.1.61      TCP      http &gt; 14023 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br><font color="#0000ff">   1298 11.809456   192.168.1.61      203.81.29.137     TCP      14022 &gt; http [FIN, ACK] Seq=1550 Ack=159770 Win=257484 Len=0<br></font>   1310 11.878665   203.81.29.137     192.168.1.61      TCP      http &gt; 14022 [FIN, ACK] Seq=159770 Ack=1551 Win=17280 Len=0<br><font color="#ff0000">   1341 12.771707   192.168.1.61      203.81.29.137     TCP      14026 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2</font><br>   1348 12.813950   203.81.29.137     192.168.1.61      TCP      http &gt; 14026 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br><font color="#0000ff">   1759 16.032952   192.168.1.61      203.81.29.137     TCP      14023 &gt; http [FIN, ACK] Seq=3151 Ack=367918 Win=257484 Len=0<br></font>   1761 16.068296   203.81.29.137     192.168.1.61      TCP      http &gt; 14023 [FIN, ACK] Seq=367918 Ack=3152 Win=17280 Len=0<br><font color="#0000ff">   1779 16.983042   192.168.1.61      203.81.29.137     TCP      14026 &gt; http [FIN, ACK] Seq=1602 Ack=208150 Win=257760 Len=0</font><br>   1781 17.016836   203.81.29.137     192.168.1.61      TCP      http &gt; 14026 [FIN, ACK] Seq=208150 Ack=1603 Win=17280 Len=0<br></pre>
</div>
<p>
</p>
<p>在这种情况下，数据包的数量非常大，连接也很多，由于没有cache功能，每次打开页面都需要重新下载所有的资源文件。
</p>
<p><strong>4. </strong><strong>选择ADE</strong>
</p>
<p>结果：共获取数据包525个，建立连接3个，断开连接3个(不再标识了，syn即为连接请求，fin即为断开请求）</p>
<div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4; max-height: 200px;">
<pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4;">No.     Time        Source            Destination       Protocol Info<br>      1 0.000000    192.168.1.61      203.81.29.137     TCP      14189 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br>      2 0.033657    203.81.29.137     192.168.1.61      TCP      http &gt; 14189 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br>      6 0.100636    192.168.1.61      203.81.29.137     TCP      14190 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br>      9 0.133703    203.81.29.137     192.168.1.61      TCP      http &gt; 14190 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br>    429 3.383748    192.168.1.61      203.81.29.137     TCP      14190 &gt; http [FIN, ACK] Seq=1852 Ack=150284 Win=257484 Len=0<br>    431 3.418556    203.81.29.137     192.168.1.61      TCP      http &gt; 14190 [FIN, ACK] Seq=150284 Ack=1853 Win=16998 Len=0<br>    471 4.352071    192.168.1.61      203.81.29.137     TCP      14189 &gt; http [FIN, ACK] Seq=1504 Ack=235576 Win=257760 Len=0<br>    472 4.380312    192.168.1.61      203.81.29.137     TCP      14192 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br>    474 4.389778    203.81.29.137     192.168.1.61      TCP      http &gt; 14189 [FIN, ACK] Seq=235576 Ack=1505 Win=17280 Len=0<br>    476 4.413220    203.81.29.137     192.168.1.61      TCP      http &gt; 14192 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br>    522 5.078068    192.168.1.61      203.81.29.137     TCP      14192 &gt; http [FIN, ACK] Seq=409 Ack=35882 Win=257760 Len=0<br>524 5.115099    203.81.29.137     192.168.1.61      TCP      http &gt; 14192 [FIN, ACK] Seq=35882 Ack=410 Win=16872 Len=0<br></pre>
</div>
<p>
</p>
<p>在这种情况下，cache发挥作用，数据包对比第三种情况大大减少，几乎等于打开一次首页的数据量（449个数据包），只有第一次打开页面需要完整下载页面（包括资源文件），后面的三次打开页面都只要下载HTML页面（不包括资源文件）。
</p>
<p>
</p>
<p><strong>5. </strong><strong>选择ADEF</strong>
</p>
<p>选择F之后我们看看结果：共获取数据包942个，建立连接4个，断开连接4个</p>
<div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4; max-height: 200px;">
<pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4;">No.     Time        Source            Destination       Protocol Info<br>      1 0.000000    192.168.1.61      203.81.29.137     TCP      14292 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br>      2 0.034524    203.81.29.137     192.168.1.61      TCP      http &gt; 14292 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br>      6 0.102314    192.168.1.61      203.81.29.137     TCP      14294 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br>      9 0.139752    203.81.29.137     192.168.1.61      TCP      http &gt; 14294 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br>    426 3.791111    192.168.1.61      203.81.29.137     TCP      14294 &gt; http [FIN, ACK] Seq=1852 Ack=150284 Win=257484 Len=0<br>    428 3.824970    203.81.29.137     192.168.1.61      TCP      http &gt; 14294 [FIN, ACK] Seq=150284 Ack=1853 Win=16998 Len=0<br>    468 6.213276    192.168.1.61      203.81.29.137     TCP      14292 &gt; http [FIN, ACK] Seq=1504 Ack=235576 Win=257760 Len=0<br>    469 6.244052    192.168.1.61      203.81.29.137     TCP      14297 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br>    471 6.249564    203.81.29.137     192.168.1.61      TCP      http &gt; 14292 [FIN, ACK] Seq=235576 Ack=1505 Win=17280 Len=0<br>    473 6.279647    203.81.29.137     192.168.1.61      TCP      http &gt; 14297 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br>    479 6.374967    192.168.1.61      203.81.29.137     TCP      14298 &gt; http [SYN] Seq=0 Len=0 MSS=1460 WS=2<br>    484 6.419597    203.81.29.137     192.168.1.61      TCP      http &gt; 14298 [SYN, ACK] Seq=0 Ack=1 Win=17280 Len=0 MSS=1440 WS=0<br>    897 9.858493    192.168.1.61      203.81.29.137     TCP      14297 &gt; http [FIN, ACK] Seq=1550 Ack=159770 Win=257484 Len=0<br>    899 9.895188    203.81.29.137     192.168.1.61      TCP      http &gt; 14297 [FIN, ACK] Seq=159770 Ack=1551 Win=17280 Len=0<br>    939 12.840029   192.168.1.61      203.81.29.137     TCP      14298 &gt; http [FIN, ACK] Seq=1806 Ack=226090 Win=257760 Len=0<br>    941 12.876120   203.81.29.137     192.168.1.61      TCP      http &gt; 14298 [FIN, ACK] Seq=226090 Ack=1807 Win=17076 Len=0<br></pre>
</div>
<p>在这种情况下，由于选择了F，在迭代的时候清除了cache，所以每次迭代都需要重新下载资源文件。数据包差不多等于第三种情况的一半，约等于打开两次首页的数据量（449&#215;2个数据包）。
</p>
<p><strong>6. </strong><strong>关于BC</strong><strong>选项</strong>
</p>
<p><strong>C</strong><strong>的解释（<em>Check for newer versions of stored pages every visit to the page</em></strong><strong><em>）</em></strong>
</p>
<p>C比较容易理解，类似IE设置中的每次检查，如果不设置C，LR对于已经cache的文件就不会重新向服务器请求，如果选择C，你就可以在数据包中发现很多304信息。
</p>
<p><strong>B</strong><strong>的解释（<em>Cache URLs requiring content(HTMLs)</em></strong><strong><em>）</em></strong>
</p>
<p>LR对于资源文件的cache并不会真正cache在内存中或者在磁盘上，这个选项表示：对于一些需要用到的关联，校验，页面解析内容真正cache在内存中，减少客户端的重复工作。
</p>
<p>当然如果你想把GIF也cache到内存中，你可以在Advanced中设置，选择Specify URL requiring
content in addition to HTML
pages，加入条目image/gif，并勾选。当Vuser运行的时候，你可以对比一下mmdrv.exe进程的内存消耗（内存占用会更多）。
</p>
<p><strong>四： 结论</strong></p>
<p>通过上面的测试分析，我们大概知道了每个选项的真正含义，你需要根据你的测试目的来选择合适的设置：
</p>
<p>1、 对于一个具体的应用测试，对于前端Web Server不可忽略，缺省设置非常合适，不需要调整（有时候需要考虑把C选上）
</p>
<p>注意：很多人在录制脚本的时候，习惯把登入操作放到vuser_init中，这时候缺省设置可能会抛错，建议把这类的操作都放入到action中
</p>
<p>2、 如果你更关注后端应用服务器的性能或者说做一些架构的验证分析，那你缺省设置对于你来说就不合适了，你需要选择取消所有的设置项。
</p>
<p>当然你也可以根据自己的具体情况做不同调整，但是一定要真正理解这些选项的具体含义才能做到不犯错误</p><img src ="http://www.cnitblog.com/stomic/aggbug/55721.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-24 21:54 <a href="http://www.cnitblog.com/stomic/archive/2009/03/24/55721.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Loadrunner Analysis——Web Page Diagnostics</title><link>http://www.cnitblog.com/stomic/archive/2009/03/23/55659.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Mon, 23 Mar 2009 09:11:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/23/55659.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55659.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/23/55659.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55659.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55659.html</trackback:ping><description><![CDATA[<p>简单介绍一下Loadrunner Analysis中的Web Page
Diagnostics模块的使用，很多人对于测试之后的结果数据分析摸不着头脑，其实loadrunner
Analysis给你提供了很好的文档，大家没事可以多翻翻，多翻几遍对于性能测试你就入门了 ；）</p>
<p>Web Page
Diagnostics （以下简称WPD），这是LR
Analysis中非常重要的一块，搞清楚这部分的内容会让你少走很多弯路，很多环境问题都可以通过它来定位，比如客户端，网络。通过它可以你可以比较好
的来定位是环境的问题还是应用本身的问题，当然更重要的是Web页面本身的问题。</p>
<p>WPD包括下面几个图表：</p>
<p>
<strong>Web Page Diagnostics</strong>&nbsp;&nbsp;&nbsp;&nbsp; 这是张总图，包括下面几张Over Time图的内容</p>
<p>
<strong>Page Component Breakdown</strong>&nbsp;&nbsp;&nbsp;&nbsp; 页面中每个元素的平均响应时间占整个页面响应时间的百分比</p>
<p>
<strong>Page Component Breakdown(Over Time)</strong>&nbsp;&nbsp;&nbsp;&nbsp;
在整个测试过程中，任意一秒内页面中每个元素的响应时间（例如在runtime中设置了browser
cache，页面中的资源文件就只会在第一次下载，后面的页面响应时间也就不包括这些元素的时间，这在Page Component
Breakdown中是看不出来的，因为Page Component
Breakdown是整个测试期间内的平均时间。当然，是否启用了cache，通过over time图就能看出来）</p>
<p>
<strong>Page Download Time Breakdown</strong>&nbsp;&nbsp;&nbsp;
页面中每个元素的响应时间分割图，响应时间被分割为以下几个部分：DNS Resolution,Connection,First
Buffer,SSL Handshaking,Receive,FTP Authentication,Client,Error</p>
<p>
<strong>Page Download Time Breakdown(Over Time)</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在整个测试过程中，任意一秒内页面中每个元素的响应时间分割图</p>
<p>
<strong>Time to First Buffer Breakdown&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong>First Buffer Time时间分割为Network Time和Server Time，客户端http请求发送到接收到服务器端的应答包（ACK）为Network Time，从接收到ACK到完成First Buffer接受为Server Time</p>
<p>
<strong>Time to First Buffer Breakdown(Over Time)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong>基本同上，任意一秒内的</p>
<p>
<strong>Downloaded Component Size(KB)</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 页面中每个元素的大小（KB）</p>
<p>介绍了这么多，具体如何分析呢？</p>
<p>首先打开Web Page Diagnostics图，来看看下面一个例子Download Time图：</p>
<p>
<a  href="http://www.blogjava.net/images/blogjava_net/tacy/WindowsLiveWriter/LoadrunnerAnalysisWebPageDiagnostics_10C05/Web-Page-Diagnostics-DownloadTime_2.png">
<img  src="http://www.blogjava.net/images/blogjava_net/tacy/WindowsLiveWriter/LoadrunnerAnalysisWebPageDiagnostics_10C05/Web-Page-Diagnostics-DownloadTime_thumb.png" style="border: 0px none ;" alt="Web-Page-Diagnostics-DownloadTime" width="644" border="0" height="265">
</a>
</p>
<p>上图存在两个问题：</p>
<p>1、receive时间很长</p>
<p>这个一般是网络问题，当然如果你确认网络不存在问题，那么你就要看看是不是客户端的问题（客户端也可能会造成Receive过长，这个千万要注意）</p>
<p>2、页面问题</p>
<p>页面上包括了非常多的图片，而且图片似乎都没有优化，最大的竟然有163K，记下来，这可是罪证哦 ；）</p>
<p>很多时候，你可以根据DNS,Connection,Receive来看出是否存在网络问题，根据Client来判断是否存在客户端问题。</p>
<p>看看，挺简单的吧！ ^_^</p>
<p>换个图看看，Page Component Breakdown(Over Time) </p>
<p>
<a  href="http://www.blogjava.net/images/blogjava_net/tacy/WindowsLiveWriter/LoadrunnerAnalysisWebPageDiagnostics_10C05/Web-Page-Diagnostics-PCB_2.png">
<img  src="http://www.blogjava.net/images/blogjava_net/tacy/WindowsLiveWriter/LoadrunnerAnalysisWebPageDiagnostics_10C05/Web-Page-Diagnostics-PCB_thumb.png" style="border: 0px none ;" alt="Web-Page-Diagnostics-PCB" width="644" border="0" height="265">
</a>
</p>
<p>很清楚吧，页面元素都被cache了，说明场景启用了browser cache，页面的响应时间只包括红线和蓝线。</p>
Time
to First Buffer Breakdown(Over Time)&nbsp;
，图就不贴了，这个图非常重要，也最复杂，这里的值不绝对，当网络状况不好的时候，server
time很可能包括网络时间，因为很多页面元素比较小（小于4k的样子），在First Buffer就完成传输，所以一定要注意分析<img src ="http://www.cnitblog.com/stomic/aggbug/55659.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-23 17:11 <a href="http://www.cnitblog.com/stomic/archive/2009/03/23/55659.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为何要在性能测试中设置考虑时间</title><link>http://www.cnitblog.com/stomic/archive/2009/03/12/55316.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Thu, 12 Mar 2009 08:52:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/12/55316.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55316.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/12/55316.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55316.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55316.html</trackback:ping><description><![CDATA[&nbsp; 考虑时间Thinking Time指的是在<a  href="javascript:;" onclick="javascript:tagshow(event, '%d0%d4%c4%dc%b2%e2%ca%d4');" target="_self"><u><strong>性能测试</strong></u></a>脚本中，事务与事务之间，会有一些短暂的停顿，就好像真实用户在操作时，两次操作之间需要考虑一下。比如用户注册的时候，在打开注册页面到提交注册页面之间，是有一段考虑时间的（用户在填写个人信息）。
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面就讨论一下在性能测试实战中，为什么要设置考虑时间。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
先说一个概念：吞吐量，这指的是服务器系统（包括软件和硬件）单位时间内处理业务的数量。我们现在做一个小试验，写一个小程序，执行一个简单的业务，并且
在程序中进行计时，计算每分钟能执行多少次。然后当我们运行1路这个程序的时候，每分钟能完成约6万次。好，现在问一个问题，如果我们起2路，是不是每一
路都能达到 6万/分钟 的吞吐量？</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 试验发现，当运行2路的时候，两个程序的数值都降了下来，但是它们的总和仍然是6万次。而且不管我们起多少路，这些程序的性能总和都接近于6万。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这就好像一个人1分钟最快能吃1个馒头，你让他一个一个吃，他两分钟能吃2个，如果你让他一手拿一个，同时吃，他两分钟吃不了4个，还是只能吃两个。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们不是在说&#8220;考虑时间&#8221;么，哈哈，别急，因为上面的问题必须要先说清楚。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果我们需要进行性能测试的业务是一个单纯的业务，就好像上面举的那个例子一样，那么测试脚本中就不需要设置&#8220;考虑时间&#8221;，因为不管你用什么方法测试，一个服务系统处理单一业务的吞吐量总是一个定值。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
但是在实际环境里面，往往一个系统都是要处理多种业务，并且这些业务之间是有逻辑关系的。举例说明，比如一个论坛系统，每天最常处理的业务有两个：A打开
帖子、B回复帖子。那么每天系统处理AB业务的总数是不是一样的呢，答案很明显，看帖子多，回复的少一些。假设A:B=2:1。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 好，如果我们不设置考虑时间，起2路A的脚本，1路B的脚本进行性能测试，我们会得到什么结果呢？我们会得到这两个业务的吞吐量，并且能算出每个小时系统完成A、B业务的总数，吞吐量 &#215; 时间 ＝ 总数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
这时我们发现，同样时间，AB业务的处理总数却不是2:1的关系，这是为什么呢？原因是这样的，我们在跑AB脚本的时候，这两组脚本都在尽全力争夺服务器
的资源，他们的并发路数虽然是2:1，但是给服务器的压力却不一定是2:1，可能会出现偏差，测试结果就是最好的证据。A查看帖子由于响应时间短，因此跑
的次数更多，最后的比例可能是4:1。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么这样的结果有什么问题呢。总结为一句话：测试环境的业务和真实环境不符，这样测出的数据没有价值。即使测试通过，也不能证明真实环境是ok的；或者即使测试不通过，也不能说明真实环境不ok，呵呵。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如上面的例子，如果我们测出的结果是B回复帖子的吞吐量不够，响应时间太长，那可能是因为A业务抢走了过多的，本不属于A的资源，而引起了B的性能降低。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说到这里，大家应该明白了，我们设置考虑时间，是为了保证测试复合业务的时候，各个业务之间的比例关系符合我们的真实生产环境。</p><img src ="http://www.cnitblog.com/stomic/aggbug/55316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-12 16:52 <a href="http://www.cnitblog.com/stomic/archive/2009/03/12/55316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>%Processor Time(Processor_Total)无法超过100%，但%Processor Time (Process _Total)能超过100%</title><link>http://www.cnitblog.com/stomic/archive/2009/03/08/55193.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Sun, 08 Mar 2009 10:07:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/08/55193.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55193.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/08/55193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55193.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55193.html</trackback:ping><description><![CDATA[<font style="font-size: 10.5pt;"><font color="#000000">% Processor Time (Processor _Total)无法超过100%，但<font style="font-size: 10.5pt;">%Processor Time (Process _Total)能超过。</font></font></font><br>
<br>
<br>
<a href="http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/core/fnef_mul_qrky.mspx?mfr=true" target="_blank"><font face="Verdana "><font size="3"><font color="#800080">Examining Processor Time Data</font></font></font></a><font face="Verdana "><font size="3"><font color="#000000">:</font></font></font><br>
<font face="Verdana "><font size="3"><font color="#000000">On
multiprocessor systems, the Processor\% Processor Time value reported
by System Monitor will never exceed 100 percent for any particular
processor or thread. On the other hand, the value of the % Processor
Time reported for the Process object can report values over 100
percent; if such values occur, this could indicate that threads of the
process are cumulatively using more than 100 percent of a processor. To
get more detailed information, use the Thread object counters to
analyze the processor time each thread within a process is using.
Investigating other data described in this section, such as DPC
activity or context switching, might help you to interpret high
processor-time values.</font></font></font><br>
<font size="3"><font color="#000000"><font face="宋体 ">多处理器系统中，由系统监视报告的处理器</font><font face="Verdana ">Processor Time%</font><font face="宋体 ">值对任何个别处理器或线程不会超出</font><font face="Verdana ">100%</font><font face="宋体 ">。另一方面，进程对象</font><font face="Verdana ">Processor Time%</font><font face="宋体 ">报告值能超出</font><font face="Verdana ">100%</font><font face="宋体 ">，如果超出就意味着该进程的这些线程在累加地超出</font><font face="Verdana ">100%</font><font face="宋体 ">使用一个处理器。要得到更详尽的信息，使用线程对象计数器去分析该处理器在一个进程里使用每个线程的时间。调查在这部分描述的其它数据，如</font><font face="Verdana ">DPC</font><font face="宋体 ">活动或上下文切换，可能会帮助你去解释高</font><font face="Verdana ">Processor Time%</font><font face="宋体 ">值。<br><br></font></font></font>
<p><strong>% Processor Time(Processor_Total)</strong><br>指处理器用来执行非闲置线程时间
的百分比。计算方法是:度量处理器用来执行空闲线程的时间，然后用100%减去该值。(每个处理器有一个空闲线程，该线程在没有其他线程可以运行时消耗周
期)。此计数器是处理器活动的主要指示器，显示在采样间隔期间所观察的繁忙时间平均百分比。应注意，对处理器是否空闲的计算是在系统时钟的内部采样间隔期
间(10ms)执行的。考虑到现在的处理器速度非常快，因此，在处理器可能会用大量时间为系统时钟采样间隔之间的线程提供服务时，%
Processor Time
会低估处理器利用率。当恰好进行采样后即向计时器发出信号时，更可能对应用程序做出不准确地度量，基于工作负荷的计时器应用程序是一个这样的示例。 </p>
<p><strong>%Processor Time (Process _Total)</strong><br><span style="display: none;">D0</span>是所有进程线程使用处理器执行指令所花的时间百分比。指令是计算机执行的基础单位。线程是执行指令的对象，进程是程序运行时创建的对象。此计数包括处理某些硬件间隔和陷阱条件所执行的代码。</p>
<p>多处理器系统中，对任何处理器或线程，系统监视器报告的Processor\% Processor
Time值不会超出100%。另一方面，进程对象(也就是Process)Processor
Time%值能超出100%；如果超出就意味着该进程的线程累计使用超出了一个处理器的100%。要得到更详尽的信息，使用线程对象计数器去分析在该进程
中每个线程的Processor
Time%值。调查在这部分描述的其它数据，如延迟过程调用(DPC)活动或上下文切换，可能会帮助你去解释高Processor Time%值。<br><br>&#8220;\Process(&#8230;)\%
Processor Time&#8221; can go up to N*100 (where N is the number of CPUs)
because it adds up the CPU usage of the requested process across all
the CPUs. <br><span style="display: none;">l,T8G&amp;X9D$L$M$N!D2K0</span>2.&#8220;\Process(_Total)\%
Processor Time&#8221; should always be around N*100 (where N is the number
CPUs) because it adds up the CPU usage of each process, including the
idle process.<br>3.&#8220;\Processor(&#8230;)\% Processor Time&#8221; can go up to 100 because it&#8217;s the CPU usage of the requested CPU. <br>&#8220;\Processor(_Total)\% Processor Time&#8221; can go up to 100 because it&#8217;s the average CPU usage across all CPUs. <br><span><strong>Processor(_Total)\% Processor Time</strong></span></p>
<p><span>This counter gives the total processor utilization figure for
the server as a whole. For example, on a dual processor system with one
processor pegged out at 100% utilization and the other processor
standing idle, a figure of about 50% would be recorded.</span></p>
<p><span>This server metric is useful for gauging overall how busy a
server is or, put in another way, how much spare capacity there is
available (by subtracting from 100%).</span></p>
<p><span>If per-processor information is required to be monitored by
Resource Manager, then additional server metrics may be configured for
monitoring:</span></p>
<p><span><strong>Processor(0)\% Processor Time</strong></span></p>
<p><span><strong>Processor(1)\% Processor Time</strong></span></p>
<p><span><strong>... etc.</strong></span></p>
<p><span>(See the Resource Manager Administrator&#8217;s Guide and the help
within the Presentation Server Console for information on Customizing
Server Metrics).</span></p>
<p><span><strong>Process Processor Utilization</strong></span></p>
<p><span>In addition to monitoring server metrics Resource Manager also
monitors process activity; one aspect of process activity monitored is
the degree to which the processor(s) is being used. </span></p>
<p><span>Processor usage of each process on the server is sampled at
regular intervals using a standard operating system call - note that
the operating system call used returns the <em>sum</em> of processor
time used by all threads within the process. Resource Manager expresses
the processor time used during the sampled interval as a percentage by
dividing this time by the elapsed time since the previous sample.</span></p>
<p><span>On a multi-processor system it is quite possible for the
percentage reported to exceed 100% in the case of a multi-threaded
process. For example, on a dual-processor system, a multi-threaded
process in which two threads are performing lengthy processor intensive
calculations would cause a value of about 200% to be recorded.</span></p>
<p><span>This process-specific processor utilization is useful for
gauging the state (and possibly health) of the process; if a process
which normally uses little processor time is seen to be consuming a
figure approaching 100%, a likely explanation is that it has
encountered a bug which has caused it to enter an uncontrolled looping
state.</span></p>
<br>  <img src ="http://www.cnitblog.com/stomic/aggbug/55193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-08 18:07 <a href="http://www.cnitblog.com/stomic/archive/2009/03/08/55193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[实用技术].NET Framework部署的性能调整</title><link>http://www.cnitblog.com/stomic/archive/2009/03/08/55192.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Sun, 08 Mar 2009 09:46:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/08/55192.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55192.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/08/55192.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55192.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55192.html</trackback:ping><description><![CDATA[<pre><a  href="http://www.microsoft.com/china/technet/itsolutions/net/Maintain/PTuneNET.asp" target="_blank">http://www.microsoft.com/china/technet/itsolutions/net/Maintain/PTuneNET.asp</a> <br><br>.NET&nbsp;Framework部署的性能调整&nbsp;<br>白皮书&nbsp;<br>Tony&nbsp;Northrup&nbsp;<br>本页内容&nbsp;<br><br>ASP.NET应用程序和Web服务&nbsp;<br>调整会话状态&nbsp;<br>Web应用程序的压力测试工具&nbsp;<br>识别系统瓶颈&nbsp;<br>使用跟踪&nbsp;<br>配置设置&nbsp;<br>构建于.NET&nbsp;Framework之上的其它应用程序&nbsp;<br>Internet信息服务&nbsp;<br>SQL&nbsp;Server&nbsp;<br>结论&nbsp;<br><br>-----------------------------------------------------------------------------<br>---<br><br>摘要&nbsp;<br>同先前的ASP程序相比，ASP.NET在性能上提供了极大的改进。虽然ASP.NET的标准配置也<br>可以提供远远超出先前环境的优异性能，但是管理员可能仍然需要对系统配置进行一些<br>调整，以实现最佳的性能表现和伸缩性。本白皮书面向系统管理员，介绍了调校构建于.<br>NET&nbsp;Framework之上的应用程序的性能所需掌握的技术，并且讨论了ASP.NET&nbsp;Web应用程<br>序、ASP.NET&nbsp;Web服务以及.NET远程应用程序。&nbsp;<br><br>ASP.NET应用程序和Web服务&nbsp;<br><br>与其它类型的应用程序相比，Web程序和Web服务的性能调整工作应当引起更多的重视和<br>注意。这些应用程序一般面向外部用户，而一个糟糕的Web站点肯定会给公司形象造成十<br>分恶劣的影响。和面向企业内部的应用程序不同，定位于外部用户的公众Web服务可能会<br>被数以百万计的用户所访问，而内部应用程序的用户数量则受公司员工规模的限制。&nbsp;<br><br>ASP.NET为系统管理员赋予了更多能力，使他们能够对Web程序和Web服务的性能和规模施<br>加更有力的控制。新的会话状态管理能力可以将有关用户访问的信息从应用程序之中完<br>全分离出来，管理员可以选择将信息存储在Web服务器的动态RAM中，存储在状态服务器<br>上，或者是存储在一个数据库中。内置的跟踪功能则允许管理员将性能问题同某段具体<br>的应用程序代码联系起来--决定性地指出问题是由应用程序而不是系统配置问题引起的<br>。&nbsp;<br><br>特别针对ASP.NET的新的性能计数器提供了有关应用程序性能的各个细节，为管理员解决<br>系统瓶颈提供了所需的信息。现有的实用工具，例如Microsoft&nbsp;Web&nbsp;Application&nbsp;<br>Stress（WAS）工具可以用来产生站点流量，在真正的用户发现站点存在的问题之前就将<br>这些问题彻底解决。由于ASP.NET既可以用来开发Web程序，也可以用来构建Web服务，管<br>理员可以直接深入到下一代Web商业的内部。本部分的内容将为管理员分析和调整各种AS<br>P.NET应用程序的提供详细的分布指导。&nbsp;<br><br>&nbsp;<br><br>调整会话状态&nbsp;<br><br>对Web应用程序和Web服务进行伸缩所需面临的最大挑战之一便是：用户状态是由多个服<br>务器进行维护的。无论Web农场采用何种配置方式，在一个会话中，针对某个用户的请求<br>总是有可能被转发到两个不同的系统上。如果所有的站点内容都是静态的，那么将不会<br>存在任何问题。但是，现在大多数的Web站点都会对用户会话进行跟踪以保存同此用户有<br>关的特定信息，例如喜好、个性化参数和购物车等。&nbsp;<br><br>先前版本的ASP允许开发人员访问会话状态信息，并且允许他们将有关用户的信息存储在<br>这个会话对象的内部。这些信息可以从站点的任何一个其它的页面上进行访问。但是，A<br>SP会将这些信息保存在Web服务器的内存之中。因此，如果使用多台Web服务器，用户的<br>请求可能就会被发送到一个与发起会话的服务器不同的其它服务器上，有关会话的信息<br>将无法获得。如果某个Web服务器重新进行了启动，它保存的所有会话信息都将丢失，这<br>对站点的正常运转会造成不可估量的影响--尤其是在您使用该会话保存用户购物车信息<br>的时候。&nbsp;<br><br>ASP.NET提供传统的单服务器会话信息，这和ASP的以前版本非常类似。此外，它还为会<br>话信息的集中提供了两个方法，这使得用户可以从Web农场或Web花园的很多不同服务器<br>上获得这些会话数据。具体使用两种方法中的哪一种完全由系统管理员来决定&nbsp;--&nbsp;它并<br>没有以代码形式固定在程序之中。所以，对于那些不是针对Web农场进行设计的ASP&nbsp;<br>.NET&nbsp;Web程序或Web服务，系统管理员可以对其进行衡量和分等。&nbsp;<br><br>ASP.NET可以使用三种方法存储会话状态信息：存储在进程中；存储在一台中央状态服务<br>器上；或者存储在SQL&nbsp;Server数据库中。将会话信息保存在进程中这种方法与传统的ASP<br>会话类似，因为会话状态信息也保存在Web服务器的内存之中，不和其它系统进行共享。<br>这种配置方法具有最佳的执行性能，因为ASP.NET不需要同网络中的其它系统通信以取得<br>会话信息。但是，这种做法限制了系统的伸缩性--会话不能跨越多台服务器，而且如果<br>用户从一台Web服务器移动到了另一台服务器上，他们的会话信息将被丢失。&nbsp;<br><br>状态服务器是运行一种特殊服务的中央服务器，该服务内置在.NET&nbsp;Framework之中。状<br>态服务器存储状态信息供Web农场中的多台服务器使用。用户可以从一台Web服务器移动<br>到另一台，而不会丢失状态信息。状态服务器引入了一些额外的工作负载，因为在每次<br>用户请求一个页面的时候，会话信息必须能够通过从Web服务器发送到状态服务器的网络<br>请求被检索和被更新。虽然需要花费一些额外工作来处理用户请求，但是系统的伸缩性<br>和可靠性却因此得到了极大的提高，因为Web应用程序可以伸缩到多个多台服务器上。&nbsp;<br><br>存储会话状态信息的第三种方法是使用一个SQL&nbsp;Server数据库。这种方法具有与使用中<br>央状态服务器相同的好处&nbsp;--&nbsp;会话可以跨越多台Web服务器进行跟踪。但是，同使用中央<br>状态服务器相比，使用SQL&nbsp;Server服务器跟踪会话产生的工作负载更大。SQL&nbsp;Server服<br>务器能够配置成群集的形式，从而提供最大限度的冗余。此外，SQL&nbsp;Server可以伸缩到<br>配备4颗处理器的高端硬件上，从而实现更多会话的并发存储。&nbsp;<br><br>以下部分针对存储会话状态信息的三种不同方法讨论了相应的性能调整措施。所有三种<br>方法可以使用同一套配置参数，并且不会对系统性能造成不良影响。用户可以使用一种<br>&#8220;无需Cookie&#8221;的方式来管理用户状态，这种方法将状态信息作为URL的一部分，而不是<br>将它们保存在一个Cookie当中。ASP.NET将会话信息插入到给定页面上所有链接的URL之<br>中&nbsp;--并且仅仅修改相对URL。因此，这种无需Cookie的状态管理不能工作在那些在一个A<br>SP.NET应用程序的内部超链接上使用绝对URL地址的站点上。&nbsp;<br><br>调整存储在进程中（In&nbsp;Process）的会话状态。&#8220;超时&#8221;设置定义了会话状态在用户进<br>行上一次请求后能够存留的时间。默认情况下，该时间被设置为20分钟。所以，如果用<br>户等上20分钟后再向服务器发送一个请求，服务器将创建一个新的会话。该设置不会影<br>响系统，特别是在使用存储在进程中的会话的时候。超时时间定义的越长，在用户不主<br>动访问您的站点期间会话中所存储信息的存活时间也就越长。但是，会话状态在进程中<br>进行维护会占用Web服务器的内存。&nbsp;<br><br>如果你的站点用户较少，但是他们的停留时间比较长，或者他们每天都定期多次访问你<br>的站点，那么你可以定义一个较长时间的超时设置。如果你的站点有成千上万的用户，<br>而且这些用户一般仅仅浏览一两个页面就离开，那么你可以设置一个较短时间的超时设<br>置。然后，请仔细监视Web服务器的运行情况，以确定对会话状态的维护是否会对系统性<br>能造成不良影响。&nbsp;<br><br>为了调整超时设置，请监视&#8220;ASP.NET应用程序&#8221;对象中的&#8220;活动会话&#8221;（Sessions&nbsp;<br>Active）计数器。该计数器指出了当前活动会话的数目，一般来说，该数目会随着超时<br>时间的增加而增多。Web服务器所能够处理的最大会话数量随存储在会话中的信息应用程<br>序数量不同而发生变化。但是，保有过多的并发会话将消耗大量的服务器内存。因此，<br>你还应该监视服务器的内存使用情况。如果在提高了会话的超时时间设置之后，内存的<br>分页操作也随之增加了，那么你应该减少会话的超时时间，或者在服务器上增加更多的<br>内存。能够对内存的分页操作进行较好表述的计数器是&#8220;内存&#8221;对象中的&#8220;每秒读取页<br>面的次数&#8221;（Page&nbsp;Reads/sec）计数器。&nbsp;<br><br>会话状态选择在machine.config或者web.config文件中定义。默认情况下，小节在machi<br>ne.config文件中被定义为&nbsp;&#8220;InProc&#8221;，这样可以为运行在单台Web服务器上的Web应用<br>程序提供最佳的性能。machine.config中的默认设置为：&nbsp;<br><br>&lt;sessionState&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mode="InProc"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stateConnectionString="tcpip=127.0.0.1:42424"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stateNetworkTimeout="10"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sqlConnectionString="data&nbsp;source=127.0.0.1;user&nbsp;id=sa;password="&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cookieless="false"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout="20"/&gt;<br><br>使用状态服务器时的会话状态配置。当你使用一台状态服务器管理会话状态的时候，&nbsp;可<br>以通过stateNetworkTimeout配置设置超时时间，时间单位为秒，ASP.NET&nbsp;Web应用程序<br>将等待状态服务器对网络请求做出响应。默认情况下，此时间被设为10秒钟。有几种原<br>因会导致状态服务器在10秒钟内不能做出响应--状态服务器过载，Web服务器过载，或者<br>状态服务器处于离线状态。如果状态服务器或者Web服务器上的流量很高（接近100%的处<br>理器利用率），并且会话状态对于ASP.NET应用程序非常重要，你可以将此超时时间提高<br>到20秒钟。&nbsp;<br><br>通常，在和状态服务器取得联系之前，ASP.NET应用程序不会将用户请求的Web页面发送<br>给用户。所以，如果状态服务器没有响应，最终用户可能必须等到网络超时之后才会接<br>收到一条错误信息。提高stateNetworkTimeout的值可以降低流量高峰期时发生错误的次<br>数；但是，在获知状态服务器离线之前，它会增加用户被迫等待的时间。如果你的Web和<br>状态服务器的超时时间得到了正确配置，你的应用程序应该可以对会话状态错误进行妥<br>善的处理。如果你的用户在看到一个页面之前没有等待10秒钟的耐心，你可以将stateNe<br>tworkTimeout从10秒钟减少到5秒钟。如果你的Web和状态服务器经常以近乎100%的CPU利<br>用率运行，并且会话状态信息对于你的ASP.NET&nbsp;Web应用程序很重要，你可以将stateNet<br>workTimeout提高到20秒。&nbsp;<br><br>状态服务器的性能监视可以使用状态服务器上的&#8220;性能&#8221;（Performance）控制台和&#8220;事<br>件查看器&#8221;（Event&nbsp;Viewer）。您可以使用&#8220;性能&#8221;控制台对&#8220;ASP.NET&#8221;对象中的&#8220;活<br>动的状态服务器会话&#8221;（State&nbsp;Server&nbsp;Sessions&nbsp;Active）计数器加以监视。此外，您<br>还可以监视处理器的利用率--既包括整体利用率（&#8220;处理器&#8221;对象中的&#8220;%&nbsp;Processor&nbsp;<br>Time&#8221;计数器，也包括每个会话状态的利用率（&#8220;进程&#8221;对象中&#8220;%&nbsp;Processor&nbsp;Time&#8221;<br>计数器内的aspnet_state.ex实例）&nbsp;。如果处理器利用率达到了100%，Web服务器将对接<br>收到的会话状态信息请求进行排队，从而损害Web站点的性能。如果状态服务器变得非常<br>忙，以至于发生请求超时现象而不能提供状态信息，将发生ID号从1072到1076的错误事<br>件，这些事件会被记录在状态服务器的应用程序事件（Application&nbsp;Event）日志中。为<br>了解决上述问题，您可以对状态服务器上的处理器进行升级。&nbsp;<br><br>为了让ASP.NET&nbsp;Web应用程序能够使用中央状态服务，您可以在应用程序的web.config文<br>件中的小节中加入以下信息。请特别注意stateConnectionString元素，它定义了状态服<br>务器的IP地址和端口号--您应该根据您自己状态服务器的实际情况修改这些属性。sqlCo<br>nnectionString属性不是一个必需的属性，因为该设置仅仅在使用SQL&nbsp;Server存储会话<br>状态信息时才发挥作用。&nbsp;<br><br>&lt;sessionState&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mode="StateServer"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stateConnectionString="tcpip=StateServerIP:42424"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stateNetworkTimeout="10"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cookieless="false"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout="20"/&gt;<br><br>使用SQL&nbsp;Server时的会话状态配置。Web农场的会话状态可以使用一台SQL&nbsp;Server服务器<br>进行管理，如果会话状态信息的重要性足以使您考虑使用冗余服务器，那么使用SQL&nbsp;<br>Server是您最佳的选择。ASP.NET&nbsp;State&nbsp;Service（状态服务）不能进行冗余配置--只能<br>使用单台状态服务器，所以如果该状态服务器发生故障变得不可用，ASP.NET&nbsp;Web应用程<br>序将无法跟踪用户会话。对这台SQL&nbsp;Server服务器的性能监视同其它SQL&nbsp;Server服务器<br>一样。有关SQL&nbsp;Server性能监视方面的更多信息，请参阅Microsoft&nbsp;Press出版的《SQL&nbsp;<br>Server&nbsp;2000&nbsp;性能调整技术指南》一书。&nbsp;<br><br>说明：如果您决定使用SQL&nbsp;Server数据库来保存会话状态信息，您应该按照本文&#8220;SQL&nbsp;<br>Profiler和Index&nbsp;Tuning&nbsp;Wizard&#8221;一节中的介绍对ASPState数据库进行调整。&nbsp;<br><br>为了让某个ASP.NET&nbsp;Web应用程序使用SQL&nbsp;Server数据库存储状态信息，请将以下信息添<br>加到该程序的web.config文件的&nbsp;小节当中。您必需修改sqlConnectionString参数，使<br>其符合标准的连接字符串格式，此外，您至少需要提供一个SQL&nbsp;Server的名称或者IP地<br>址，以及一个合法的用户名和口令。为了改善系统的安全性，您应该在SQL&nbsp;Server上创<br>建一个具有最小权限的账户，而不是使用SA账户完成这一切。&nbsp;<br><br>&lt;sessionState&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mode="SqlServer"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sqlConnectionString="data&nbsp;source=SQLServerIP;user&nbsp;<br>id=Username;password=Password"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stateNetworkTimeout="10"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cookieless="false"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout="20"/&gt;<br><br>&nbsp;<br><br>Web应用程序的压力测试工具&nbsp;<br><br>Microsoft&nbsp;WAS工具是Microsoft&nbsp;发布的一个免费工具，可以在Web服务器上产生流量负<br>载。该工具可以模拟数百个或数千个用户同时对您的站点进行的访问，然后生成一个带<br>有性能信息的汇总报告。通过在Web服务器上施加额外负载并监视其性能的变化，你可以<br>确定如何对应用程序进行伸缩，以及哪些资源会对系统的伸缩性造成限制。WAS工具可以<br>从以下地址免费下载：&nbsp;<br><a  href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e2c0585a-062a-439e-a" target="_blank">http://www.microsoft.com/downloads/details.aspx?FamilyID=e2c0585a-062a-439e-a</a> <br>67d-75a89aa36495&amp;DisplayLang=en.&nbsp;本节内容将介绍使用WAS工具为ASP.NET页面的呈现<br>建立一个基准和加载测试用ASP.NET&nbsp;Web服务的具体方法。如需获得使用WAS工具的更详<br>细指导，请参阅：<a  href="http://msdn.microsoft.com/library/en-us/dnduwon/html/d5wast_2" target="_blank">http://msdn.microsoft.com/library/en-us/dnduwon/html/d5wast_2</a> <br>.asp.&nbsp;<br><br>WAS可以用来测试任何类型的Web服务器。测试ASP.NET&nbsp;Web程序和测试其它Web程序没有<br>什么太大的不同--但是系统管理员在调整ASP.NET程序的性能时应该对WAS报告中的几个<br>关键部分加以特别的重视。WAS报告中的&#8220;页面摘要&#8221;（Page&nbsp;Summary）部分列出了测试<br>期间被请求的所有页面、页面被请求的次数、传送首字节的时间（Time&nbsp;To&nbsp;First&nbsp;<br>Byte&nbsp;，TTFB）和传送末字节的时间（Time&nbsp;To&nbsp;Last&nbsp;Byte，TTLB）。TTFB指标可以用来<br>断定Web服务器提交一个ASP.NET页面所需花费的时间。为了获得该时间，您可以：&nbsp;<br><br>在ASP.NET&nbsp;Web服务器所在局域网中的一台计算机上安装WAS。&nbsp;<br>创建一个WAS脚本，该脚本可以对站点上您希望测量的所有.ASPX页面进行查询。&nbsp;<br>选择脚本设置，然后将&#8220;压力级别&#8221;（Stress&nbsp;Level）和&#8220;压力倍数&#8221;（Stress&nbsp;<br>Multiplier）设置为1，如图1所示。这将迫使WAS使用单个客户端请求所有页面，以确保<br>不会同时请求多个页面。&nbsp;<br><br>如果你的浏览器不支持内联框架，请&nbsp;点击此处在单独的页面中查看。&nbsp;<br>图1&nbsp;将WAS配置为只使用一个客户端是创建ASP.NET&nbsp;Web程序性能基准测试的一种优秀方<br>法。&nbsp;<br><br>接下来，在&#8220;测试时间&#8221;（Test&nbsp;Run&nbsp;Time）下，将时间值设定为5分钟。这样可以获得<br>一个数量合理的取样点数目。&nbsp;<br>在&#8220;暂停&#8221;（Suspend）下，将&#8220;预热&#8221;（Warmup）时间设定为1分钟，以确保在您开始<br>测量之前每个页面均被请求了数次。ASP.NET页面在初次请求时需要进行编译--因此，第<br>一次获得所请求页面的时间特别长，您不应该使用这些时间来建立性能基准。预热期还<br>会产生各种缓存，这些缓存将在以后的时间发挥效力。&nbsp;<br>点击工具栏&#8220;运行脚本&#8221;（Run&nbsp;Script）按钮。脚本将被执行。&nbsp;<br>在脚本完成之后，请点击&#8220;报告&#8221;（Reports）选项卡，然后选择新的报告。向下滚动内<br>容直到&#8220;页面摘要&#8221;（Page&nbsp;Summary）部分，如图2所示。每个页面的TTFB数值是以毫秒<br>为单位的时间值，在轻负载的情况下，您的ASP.NET应用程序需要花费这些时间为用户提<br>交页面。&nbsp;<br><br>如果你的浏览器不支持内联框架，请&nbsp;点击此处在单独的页面中查看。&nbsp;<br><br>图2&nbsp;TTFB&nbsp;Average指标指出了提交ASP.NET页面所需花费的时间。&nbsp;<br><br>在轻负载情况下测量TTFB可以建立一个基准。将轻负载下的TTFB值与重负载情况下的TTF<br>B值相比较，您便可以了解到应该如何对Web应用程序进行伸缩，以及这种伸缩将会对最<br>终用户的Web体验产生何种影响。如果TTFB值高于1000毫秒（即1秒钟），在正常流量情<br>况下，产生ASP.NET页面所需的时间便有可能对用户的浏览体验产生影响。通过升级Web<br>服务器的处理器、调整数据库访问方式以及采取本文介绍的其它方法，这个时间可以被<br>降低。&nbsp;<br><br>在你打开WAS报告的时候，请注意该报告的&#8220;结果代码&#8221;（Result&nbsp;Codes）部分。唯一应<br>该被列出的结果代码是&#8220;200&#8221;--表明所有的请求都已经成功完成。随后，当你在更高的<br>负载下运行此测试的时候，你将可以看到一些错误，这表明该ASP.NET已经到达了它的能<br>力上限。为了提高服务器的工作负载，你可以选择&#8220;设置&#8221;（Settings），然后增加&#8220;<br>压力级别&#8221;（Stress&nbsp;Level）和&#8220;压力倍数&#8221;（Stress&nbsp;Multiplier）的数值。你可以逐<br>步提高这些设置，并且将得到的结果同第一次测试得到的基准结果进行对比，了解站点<br>性能是如何随着流量增加而变慢的。应用程序瓶颈的识别方法，请遵照本文&#8220;识别系统<br>瓶颈&#8221;部分中的指导进行操作。&nbsp;<br><br>WAS还可以用来测试ASP.NET&nbsp;Web服务。默认情况下，当浏览器请求一个.ASMX文件时，AS<br>P.NET&nbsp;Web服务会生成一个可视的页面。用户可以在表单域中输入信息，然后请求会被调<br>用的Web服务进行处理。这些自动生成的页面使用HttpGet&nbsp;Web服务协议，该协议是ASP.N<br>ET&nbsp;Web服务默认使用的协议。WAS可以使用该接口模拟由多个并发客户端发出的Web服务<br>请求，如图3所示。针对现有的Web服务生成WAS脚本的最容易方法是使用WAS记录你在浏<br>览器中手动输入的这些请求，然后删除请求路径中的&#8220;？&#8221;字符后面不包括参数的任何<br>步骤。如果你的Web服务客户端使用了HttpSoap方法，结果将不是一种完美的模拟。但是<br>，对于识别性能瓶颈来说，它仍然不失为一种有用的手段。&nbsp;<br>如果你的浏览器不支持内联框架，请&nbsp;点击此处在单独的页面中查看。&nbsp;<br><br>图3&nbsp;通过创建一个脚本，利用合适的参数发出对.ASMX文件的请求，WAS可以对使用HTTPG<br>et方法的Web服务进行测试。&nbsp;<br><br>&nbsp;<br><br>识别系统瓶颈&nbsp;<br><br>无论您是采用Microsoft&nbsp;WAS工具来人为地产生一些流量，或者是已经拥有了一个繁忙的<br>站点，对负载情况下Web服务器的性能进行监视均是很重要的。监视服务器资源利用率的<br>最佳工具是性能控制台。在Windows&nbsp;2000中，您可以点击&#8220;开始&#8221;按钮、将鼠标指向&#8220;<br>程序&#8221;，选择&#8220;管理工具&#8221;，然后点击&#8220;性能&#8221;，以启动该控制台。在Windows&nbsp;<br>Server&nbsp;2003中，您可以点击&#8220;开始&#8221;按钮，指向&#8220;所有程序&#8221;，选择&#8220;管理工具&#8221;，然<br>后点击&#8220;性能&#8221;。表1给出了识别ASP.NET应用程序瓶颈所需的最重要性能计数器。&nbsp;<br><br>表1&nbsp;识别系统瓶颈所用到的性能计数器&nbsp;<br><br><br>对象&nbsp;计数器&nbsp;描述&nbsp;<br>处理器&nbsp;%&nbsp;利用率百分比&nbsp;本指标指出了Web服务器上处理器的总体利用率。处理器是ASP.<br>NET&nbsp;Web服务器上最为常见的瓶颈所在。如果当Web处理负载时该计数器的峰值数值接近1<br>00%&nbsp;，您就应该添加&#8220;进程&#8221;对象中的&#8220;%&nbsp;Processor&nbsp;Time&#8221;计数器，以确定出究竟是<br>哪一个进程拖累了服务器的性能。&nbsp;<br>进程&nbsp;%&nbsp;处理器时间百分比&nbsp;本计数器提供的信息与&#8220;%&nbsp;CPU&nbsp;Utilization&#8221;计数器类似，<br>但是它可以识别出具体是哪一个进程耗用了大部分的CPU时间。为了确保能够收集到所需<br>的全部信息，您应该在添加该计数器时，选中&#8220;添加计数器&#8221;（Add&nbsp;Counters）对话框<br>中的&#8220;所有实例&#8221;（All&nbsp;Instances）单选按钮。如果aspnet_wp&nbsp;进程占用了大部分处理<br>器时间，这就清楚地说明了ASP.NET页面的呈现是系统的瓶颈所在。如果inetinfo进程出<br>现问题，说明是IIS引起的问题。这些问题可以通过升级Web服务器的CPU、增加多个CPU<br>或者添加更多Web服务器得到解决。如果你的ASP.NET应用程序是由数据库驱动的，并且<br>你在相同系统上运行一个Microsoft&nbsp;SQL&nbsp;Server，你很可能会发现名为sqlservr的进程<br>是引起CPU瓶颈的罪魁祸首。对这种情况的最佳补救方法便是将SQL&nbsp;Server移动到另一台<br>服务器上。或者，升级处理器或者增添更多的处理器也有助于改善这种情况。&nbsp;<br>ASP.NET应用程序&nbsp;每秒的请求数&nbsp;本计数器可以测量ASP.NET请求的接收速度，对于在过<br>载情况下测量Web应用程序的峰值处理能力来说，它也是一种有用的手段。该计数器只会<br>报告针对特定文件的请求数目，这些传递给ASP.NET的文件的扩展名在IIS中进行配置，<br>大多数情况下，它们是一些.ASPX和.ASMX文件。为了查看总的请求数，包括对图像文件<br>的请求，您可以使用&#8220;Web服务&#8221;对象中的&#8220;Get&nbsp;Requests/sec&#8221;计数器代替本计数器。<br>&nbsp;<br>ASP.NET应用程序&nbsp;活动会话的数目&nbsp;此计数器用来测量当前处于活动状态的ASP.NET会话<br>的数目。会话是在新的用户发出第一次请求时由ASP.NET程序建立的。会话一直存活，直<br>到：1)&nbsp;当用户退出登录时，程序明确地放弃了该会话，或者2)在会话超时时间内没有从<br>用户处接收到任何请求。默认情况下，ASP.NET的会话将在20分钟后超时。用户可以修改<br>web.config或machine.config文件中元素的sessionState属性来调整该设置。有关会话<br>和超时时间设置的更多信息，请参看本文的&#8220;调整会话状态&#8221;一节。&nbsp;<br>ASP.NET&nbsp;队列中请求的数目&nbsp;本计数器指出了当呈现一个页面所需的时间超过了所接受的<br>两个客户端请求之间的时间间隔之后，在队列中进行排队的请求数目。在正常的Web流量<br>下，用户发出请求的速度是不确定的，在最繁忙的时刻，几秒钟内就会发生排队现象。<br>这使得提交页面的时间临时性地增加了，但是在接下来的空闲时段，队列又会很快被消<br>除。负载测试工具（例如WAS）产生的流量一般比较稳定，所以可能引起ASP.NET的&#8220;Req<br>uests&nbsp;Queued&#8221;计数器持续攀升，尽管在实际的应用情境之中，这种情况可能并不会出<br>现。为了模拟这些随机出现的流量高峰和低谷，您可以在WAS的&#8220;脚本设置&#8221;页中选中&#8220;<br>使用随机延迟&#8221;（Use&nbsp;Random&nbsp;Delay）复选框。如果在启用了该设置之后，该计数器的<br>数值仍然继续增加，说明该服务器当前的工作负载已经超出了它的能力范围，它将成为<br>一个系统瓶颈，您应该在继续测试之前解决这个瓶颈问题。默认情况下，ASP.NET的队列<br>长度最大可以容纳100个请求。您可以修改web.config或machine.config文件中httpRunT<br>ime元素的appRequestQueueLimit属性来改变这一限制。&nbsp;<br>ASP.NET&nbsp;被拒绝的请求数&nbsp;在ASP.NET请求队列被充满之后，新的请求将被拒绝。对于极<br>高负载的情况，这种处理方法对于ASP.NET一般都是正确的，因为它会立即向用户返回一<br>个错误，并且从Web服务器的队列之中删除该请求，而不是强迫用户等待，直到浏览器超<br>时。对本计数器进行监视可以获知在队列长度达到最大之后，Web服务器所接受到请求总<br>数是多少。&nbsp;<br><br>&nbsp;<br><br>使用跟踪&nbsp;<br><br>ASP.NET&nbsp;Web程序和Web服务能够对请求和响应进行强有力的跟踪。虽然跟踪工具面向开<br>发人员，主要是为他们解决程序错误和优化程序性能提供的，但是它也可以被系统管理<br>员用来向开发人员提供有关程序性能的特定反馈意见。启用跟踪会增加系统的性能负载<br>，并且可能会暴露一些私人信息，所以只有在对一个程序进行主动分析时，才应该启用<br>跟踪。为了启用程序跟踪，您可以在该程序的web.config文件的小节中添加或者编译如<br>下一些元素：&nbsp;<br><br>&lt;trace<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enabled="true"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requestLimit="10"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pageOutput="false"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;traceMode="SortByTime"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localOnly="true"<br>/&gt;<br><br>必须进行修改的关键属性是enabled=&#8221;true&#8221;。如果您直接连接到Web服务器的桌面，请<br>设置localOnly=&#8221;true&#8221;属性。该设置确保了远程用户不能访问有关应程序的细节信息<br>。您也可以通过使用localOnly=&#8221;false&#8221;设置让远程系统能够查看跟踪信息，但是这样<br>做具有一些潜在的安全风险，可能会把跟踪信息暴露给外界。pageOutput=&#8221;false&#8221;&nbsp;设<br>置是针对生产用服务器的唯一安全设置；但是，你可以在开发服务器上使用pageOutput=<br>&#8221;true&#8221;&nbsp;设置，以在每一个ASP.NET页面的底部查看跟踪信息。requestLimit=&#8221;10&#8221;&nbsp;<br>的默认设置规定了只有同前10个ASP.NET请求有关的信息会被存储。如果需要，你可以提<br>高此数值；但是，这样做会增加跟踪工作的工作量。&nbsp;<br><br>在对某个程序进行跟踪的时候，你可以从一个应用程序的根目录那里请求一个特殊的页<br>面，即trace.axd。为了在Web服务器上的浏览器中查看该页面，您可以打开如下URL地址<br>：&nbsp;<a  href="http://localhost/trace.axd%E3%80%82%E4%BD%A0%E4%BC%9A%E7%9C%8B%E5%88%B0%E4%B8%80%E4%B8%AA%E4%B8%BB%E8%B7%9F%E8%B8%AA%E9%A1%B5%E9%9D%A2%EF%BC%8C%E5%A6%82%E5%9B%BE4%E6%89%80%E7%A4%BA%E3%80%82%E8%AF%B7%E6%B3%A8%E6%84%8F%EF%BC%9Atra" target="_blank">http://localhost/trace.axd。你会看到一个主跟踪页面，如图4所示。请注意：tra</a> <br>ce.axd文件实际上并没有真的存在于应用程序的根目录下--该请求被ASP.NET截取了，并<br>且进行了动态处理。&nbsp;<br>如果你的浏览器不支持内联框架，请&nbsp;点击此处在单独的页面中查看。&nbsp;<br><br>图4&nbsp;应用程序跟踪是深入应用程序逻辑，揭开性能瓶颈根源的有用方法。&nbsp;<br><br>当你点击请求的&#8220;查看详细信息&#8221;（View&nbsp;Details）连接时，你将会看到&#8220;请求详细信<br>息&#8221;（Request&nbsp;Details）页面。该页面提供了有关ASP.NET页面组成和它的底层组件的<br>非常详尽的信息。在&#8220;跟踪信息&#8221;（Trace&nbsp;Information）部分，如图5所示，展示了页<br>面呈现的每个阶段所需花费的时间。应用程序开发人员还可以在此部分中插入特定于应<br>用程序的信息，以允许管理员发现开发人员代码中存在的性能问题。在跟踪信息部分，<br>请检查&#8220;From&nbsp;Last(s)&#8221;列以确定完成哪一个阶段需要花费的时间最长。&nbsp;<br><br>说明：默认情况下，ASP.NET&nbsp;Web程序（.ASPX文件）会产生很多有用的跟踪信息。管理<br>员还可以跟踪ASP.NET&nbsp;Web服务（.ASMX文件），但是除非开发人员在Web服务中明确地整<br>合进了跟踪能力，否则&#8220;Trace&nbsp;Information&#8221;和&#8220;Control&nbsp;Tree&#8221;（控件树）部分将是<br>一片空白。&nbsp;<br>如果你的浏览器不支持内联框架，请&nbsp;点击此处在单独的页面中查看。&nbsp;<br><br>图5&nbsp;&#8220;请求详细信息&#8221;的&#8220;跟踪信息&#8221;部分使得管理员能够将问题原因缩小到某个特定<br>的页面上。&nbsp;<br><br>&#8220;请求详细信息&#8221;页面的下一个部分是&#8220;控件树&#8221;（Control&nbsp;Tree），如图6所示。控件<br>树列出了页面调用的每一个控件的名称、类型、控件生成的HTML字符数量以及viewstate<br>的字节大小。ASP.NET页面一般由不同的控件组成。一个ASP.NET控件可以是一个表格、<br>一个超链接、一个工具栏或者能够包括在Web页面中的其它任何东西。&nbsp;<br>如果你的浏览器不支持内联框架，请&nbsp;点击此处在单独的页面中查看。&nbsp;<br><br>图6&nbsp;&#8220;控件树&#8221;展示了给定页面上每个控件的细节。&nbsp;<br><br>Viewstate是一个插入到HTML之中的隐藏字段，ASP.NET用它来跟踪页面的当前设置。程<br>序开发人员经常在不需要它的控件上启用viewstate，这会造成页面产生不必要的臃肿，<br>而控件树则有助于解决这些问题。在控件树的下方，&#8220;请求详细信息&#8221;页面显示了同页<br>面和请求有关的每一件事情。这些信息对于解决程序错误和分析性能问题十分有用。&nbsp;<br><br>说明：在完成所有工作之后，不要忘记在元素中设置enabled=&#8221;false&#8221;属性。&nbsp;<br><br>&nbsp;<br><br>配置设置&nbsp;<br><br>系统管理员能够对ASP.NET程序施加强有力的控制。决定应用程序性能的很多方面都可以<br>通过machine.config和web.config文件进行配置。有关ASP.NET配置的一般性信息，请参<br>阅<a  href="http://support.microsoft.com/directory/article.asp?ID=KB" target="_blank">http://support.microsoft.com/directory/article.asp?ID=KB</a> EN-US;Q307626&amp;.&nbsp;在<br>本节之中，我们将介绍三种可以极大影响ASP.NET性能的配置设置：调试、进程模型以及<br>数据源配置。&nbsp;<br><br>禁用调试。ASP.NET包括了一个特殊的调试模式，来帮助开发人员解决程序中存在的问题<br>。调试模式会增加系统负载，并降低系统的整体性能，在投入实际生产应用的ASP.NET&nbsp;<br>Web服务上，应该禁用调试模式。调试模式在machine.config文件的部分中开放的标签中<br>设置，可以通过将该小节添加到web.config文件中取代此设置。在禁用调试模式以后，<br>开放的&#8220;compilation&#8221;标签应该包括debug=&#8221;false&#8221;元素，并且可能包含其它非相关<br>的元素，如下所示：&nbsp;<br><br>&lt;compilation&nbsp;debug="false"&nbsp;explicit="true"&nbsp;<br>defaultLanguage="vb"&gt;&nbsp;<br><br>配置进程模型。如果ASP.NET运行在Windows&nbsp;2000环境下的IIS&nbsp;5.0&nbsp;Server上，machine.<br>config文件的部分中的元素可以包含几个有用的配置设置。在Windows&nbsp;Server&nbsp;2003和II<br>S&nbsp;6.0中，这些项目可以通过Internet信息服务（IIS）的管理工具进行配置。简而言之<br>，ASP.NET进程模型可以自动回收利用应用程序，收回丢失的内存和资源。此外，它能够<br>将ASP.NET被限制到一个多处理器系统中的某几个特定处理器上。大多数的管理员不需要<br>为了优化系统性能而修改machine.config文件中的这一部分。此部分包括了大部分可用<br>于性能调整的有用配置属性。&nbsp;<br><br>说明：machine.config文件中的大多数元素都可以通过在web.config文件中放置元素内<br>容而被取代。默认情况下，&nbsp;元素可以仅仅在machine.config文件中定义。&nbsp;<br><br>的默认设置如下：&nbsp;<br><br>&lt;processModel&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enable="true"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout="Infinite"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idleTimeout="Infinite"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shutdownTimeout="0:00:05"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requestLimit="Infinite"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requestQueueLimit="5000"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;restartQueueLimit="10"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memoryLimit="60"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;webGarden="false"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cpuMask="0xffffffff"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userName="machine"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password="AutoGenerate"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logLevel="Errors"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clientConnectedCheck="0:00:05"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;comAuthenticationLevel="Connect"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;comImpersonationLevel="Impersonate"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseRestartDeadlockInterval="00:09:00"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseDeadlockInterval="00:03:00"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxWorkerThreads="25"&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxIoThreads="25"/&gt;<br><br>表2&nbsp;属性&nbsp;<br><br><br>属性名称&nbsp;默认设置&nbsp;描述&nbsp;<br>cpuMask&nbsp;0xffffffff。本设置会导致ASP.NET为Web服务器上的每一颗处理器启动一个单<br>独的ASP.NET进程。&nbsp;用来将ASP.NET限制到多处理器系统中的某些特定处理器上。只有在<br>webGarden属性设置为&#8220;false&#8221;之后，该属性才会起作用。如果ASP.NET和SQL&nbsp;Server运<br>行在同一个系统上，并且SQL&nbsp;Server使用了相反的cpuMask设置，设置本属性可能会改善<br>系统的性能表现为了计算出需要的cpuMask值，您可以使用附件中的计算器，并且将其设<br>置为科学模式。然后选择二进制计算模式，为ASP.NET将要使用的每一颗处理器输入一个<br>&#8220;1&#8221;。为每一颗不会被用到的处理器输入一个&#8220;0&#8221;。然后，将这个数字转换成16进制<br>，并且据此修改machine.config文件中的本元素值。请确信你输入的数字是以&nbsp;&#8216;0x&#8217;&nbsp;<br>开头的，以表明你输入的是一个16进制的数。&nbsp;<br>webGarden&nbsp;false&nbsp;本设置会导致ASP.NET使用cpuMask属性来识别应该为ASP.NET使用哪些<br>处理器。如果将本属性设置为&#8220;true&#8221;，ASP.NET将使用Windows操作系统自身的调度机<br>制。&nbsp;<br>requestQueueLimit&nbsp;5000&nbsp;如果ASP.NET接受请求的速度大于它响应请求的速度，那么，<br>这些请求将进入队列排队，直到有空闲的处理能力对它们进行处理为止。如果队列的增<br>长超过了特定的规模，ASP.NET将使用一个&#8220;服务器过于繁忙&#8221;的错误响应用户的请求。<br>根据应用程序的不同，发送这样的一个错误可能要比强迫用户等待服务器响应要好很多<br>。&nbsp;<br>serverErrorMessageFile&nbsp;没有设定-&nbsp;交由ASP.NET进行动态处理&nbsp;如果发生一个错误，文<br>件的绝对路径将会发送给用户，例如，在requestQueueLimit属性达到设定值的时候。管<br>理员应该使用本设置为用户提供友好的错误信息，通知他们发生了什么问题，并且提醒<br>他们在稍候的时间再次进行尝试。&nbsp;&nbsp;<br><br>配置数据源。&nbsp;某些应用程序允许管理员定义数据源。如果一个ASP.NET程序既可以使用O<br>LEDB数据源，也可以使用固有的SQL数据源，那么您应该尽可能地使用SQL数据源。与使<br>用在ODBC数据源管理器中进行配置的数据源名称（DSN）相比，使用ASP.NET内置的SQL客<br>户端可以将系统性能提高50%之多。不幸的是，在指示应用程序应该以何种方式访问数据<br>方面，目前还没有一种连续一致方法可供使用，所以，请参考该应用程序的文档。&nbsp;<br><br>&nbsp;<br><br>构建于.NET&nbsp;Framework之上的其它应用程序&nbsp;<br><br>专为ASP.NET基础结构设计的应用程序为系统管理员调整程序性能赋予了更多的控制能力<br>。但是，还有很多应用程序不使用ASP.NET。例如，.NET&nbsp;远程Web服务便没有利用ASP.NE<br>T，因此，如果希望分析这些应用程序的性能表现，监视ASP.NET性能计数器并不是一个<br>好的办法。此外，.NET远程应用程序不支持HttpGet&nbsp;Web服务协议，所以也不能使用WAS<br>为这些程序产生负载。事实上，对于.NET远程程序，系统管理员必须依靠程序开发人员<br>才能完成大量的性能分析和调整工作。但是，通用语言运行时（Common&nbsp;Language&nbsp;<br>Runtime，CLR）却提供了几个有用的性能计数器，如表3所示。&nbsp;表3&nbsp;CLR提供的性能计数<br>器&nbsp;<br><br><br>对象&nbsp;计数器&nbsp;描述&nbsp;<br>.NET&nbsp;CLR&nbsp;Remoting&nbsp;&nbsp;Remote&nbsp;Calls/sec&nbsp;用来测量接收远程请求的当前速度。本计数器<br>使得管理员能够精确地测量出应用程序的当前负载。&nbsp;<br>Process&nbsp;%&nbsp;Processor&nbsp;Time&nbsp;该计数器可以测量某个特定进程消耗的处理器百分比。每一<br>个.NET远程程序都有一个唯一的进程名称，该名称同程序可执行文件的名称相匹配。对<br>&#8220;Remote&nbsp;Calls/sec&#8221;计数器和&#8220;%&nbsp;Processor&nbsp;Time&#8221;计数器进行监视可以帮助系统管<br>理员更好地理解每个远程调用所需花费的处理时间。&nbsp;<br>.NET&nbsp;CLR&nbsp;Networking&nbsp;Bytes&nbsp;Sent,&nbsp;Bytes&nbsp;Received&nbsp;&#8220;Bytes&nbsp;Sent&#8221;和&#8220;Bytes&nbsp;<br>Received&#8221;计数器可以测量由所有的.NET&nbsp;CLR应用程序产生的网络流量，这对于测量程<br>序产生的流量大小很有帮助。它并不包括ASP.NET&nbsp;Web应用程序和Web服务产生的流量。&nbsp;<br><br>.NET&nbsp;CLR&nbsp;LocksAndThreads&nbsp;Total&nbsp;#&nbsp;of&nbsp;Contentions,&nbsp;Current&nbsp;Queue&nbsp;Length&nbsp;运行在C<br>LR中的所有应用程序所发生争用的数目。对于健康的应用程序，发生系统资源的争用是<br>一件正常的事情。但是，如果在发生间歇性的性能问题期间，该数字保持上升，就说明<br>某个关键的系统资源被某一个程序锁定了。这可能是某个应用程序低效使用系统资源的<br>标志，可以由程序开发人员来纠正这一问题。&nbsp;<br>.NET&nbsp;CLR&nbsp;Data&nbsp;SqlClient:&nbsp;Current&nbsp;#&nbsp;pool&nbsp;and&nbsp;nonpooled&nbsp;connections&nbsp;测量.NET程<br>序的活动SQL连接的数目，包括ASP.NET程序。&nbsp;<br><br>&nbsp;<br><br>Internet信息服务&nbsp;<br><br>IIS是ASP.NET&nbsp;Web程序、ASP.NET&nbsp;Web服务和很多.NET远程程序的重要组成部分。理解II<br>S性能调整的重要性是实现高性能.NET程序的关键。对IIS进行的调整并不仅仅针对ASP.N<br>ET一家，而且已经有大量的相关文档可供学习。因此，这一部分的内容不是本文的讲述<br>重点。有关IIS性能调整的更详细信息，请阅读题为&#8220;利用IIS5.0对Web服务器进行性能<br>调整的艺术和科学&#8221;的白皮书，该白皮书可从以下地址获得。<a  href="http://www.microsoft.co/" target="_blank">http://www.microsoft.co</a> <br>m/windows2000/techinfo/administration/web/tuning.asp.&nbsp;<br><br>&nbsp;<br><br>SQL&nbsp;Server&nbsp;<br><br>构建于.NET&nbsp;Framework之上的大部分应用程序都连接到SQL&nbsp;Server上检索数据。在很多<br>情况下，数据库或者数据库连接会成为程序的性能瓶颈。对于由数据驱动的程序，理解S<br>QL&nbsp;Server的性能问题对程序整体性能的调整有着不言而喻的重要意义。程序开发人员对<br>使用何种方法从SQL&nbsp;Server数据库中取得数据有着很大的发言权，而他们所做出的选择<br>对程序的整体性能有着极其重要的影响。虽然程序进行的某个特定查询一般不能由系统<br>管理员进行修改，但是你可以分析一个.NET程序对数据库所发出请求的类型，并且据此<br>对索引方式加以调整。本节内容将给出有关SQL&nbsp;Server索引调整的一个详细的分布指导-<br>-&nbsp;一种可能会迅速提高程序性能的方法。有关SQL&nbsp;Server性能的详细信息，请阅读Micro<br>soft&nbsp;Press出版发行的SQL&nbsp;Server&nbsp;2000性能调整技术指南一书。&nbsp;<br><br>改善SQL&nbsp;Server性能的一种容易方法是结合使用索引调整向导（Index&nbsp;Tuning&nbsp;Wizard）<br>和SQL&nbsp;Profiler。Profiler可以记录SQL&nbsp;Server接收到的查询，并且将它们记录在一个<br>文件或者数据库的一个表中。索引调整向导能够分析这些文件，找出应该对数据库设计<br>进行的修改，以改善数据库性能，同时允许系统管理员选择最为适合的修改方式。这些<br>工具的运行会增加数据库的工作负载，所以您不应该在负荷已经接近最大处理能力的生<br>产系统中运行这些工具。为了使用Profiler和Index&nbsp;Tuning&nbsp;Wizard优化您的数据库设计<br>，您应该：&nbsp;<br><br>登录到SQL&nbsp;Server的控制台中。&nbsp;<br>点击&#8220;开始&#8221;按钮，指向&#8220;程序&#8221;，指向&#8220;Microsoft&nbsp;SQL&nbsp;Server&#8221;，然后点击&#8220;Profi<br>ler&#8221;。&nbsp;<br>打开&#8220;文件&#8221;菜单，点击&#8220;新建&#8221;，选择&#8220;跟踪&#8221;，以创建一个新的跟踪。&nbsp;<br>在&#8220;连接到SQL&nbsp;Server&#8221;对话框中，选择您的SQL&nbsp;Server和身份验证方法，然后点击&#8220;<br>确定&#8221;。&nbsp;<br>在&#8220;跟踪属性&#8221;对话框中，从模板名称下拉列表中选择&#8220;SQLProfilerTuning&#8221;。选中&#8220;<br>保存到文件&#8221;复选框，然后在&#8220;另存为&#8221;对话框中输入一个新的文件名。点击&#8220;保存&#8221;<br>。&nbsp;<br>点击&#8220;运行&#8221;按钮开始记录发送给SQL&nbsp;Server的请求，如图7所示。如果你的程序当前处<br>于活动状态，请让优化器运行足够长的时间，以便至少能够收集到100行的数据。如果您<br>的程序当前没有在运行，请以一种最为典型的方式启动该程序以产生数据请求。&nbsp;<br><br>如果你的浏览器不支持内联框架，请&nbsp;点击此处在单独的页面中查看。&nbsp;<br>图7&nbsp;Profiler收集SQL请求供Index&nbsp;Tuning&nbsp;Wizard分析使用。&nbsp;<br><br>在收集到足够的请求之后，点击工具栏上的&#8220;停止&#8221;按钮。从&#8220;工具&#8221;菜单中，选择&#8220;I<br>ndex&nbsp;Tuning&nbsp;Wizard&#8221;（索引调整向导）。该向导将出现，如图8所示。点击&#8220;下一步&#8221;<br>按钮，然后在接到提示时选择你的数据库服务器。&nbsp;<br><br>如果你的浏览器不支持内联框架，请&nbsp;点击此处在单独的页面中查看。&nbsp;<br>图8&nbsp;Index&nbsp;Tuning&nbsp;Wizard分析由Profiler产生的工作负载文件，并且对如何修改索引以<br>改善性能提出建议。&nbsp;<br><br>在Index&nbsp;Tuning&nbsp;Wizard页中，从&#8220;数据库&#8221;列表中选择应用程序最常使用的数据库。如<br>果你的应用程序需要同一个以上的数据库展开通信，你应该在每一个数据库上重复上述<br>过程。然后点击&#8220;下一步&#8221;按钮。&nbsp;<br>在&#8220;指定工作负载&#8221;页中，选择&#8220;我的工作负载文件&#8221;（My&nbsp;Workload&nbsp;File）单选按钮<br>。在&#8220;打开&#8221;对话框中，选择你在步骤5中指定的文件。点击&#8220;打开&#8221;按钮，然后点击&#8220;<br>下一步&#8221;。&nbsp;<br>在&#8220;选择需要调整的数据表&#8221;（Select&nbsp;Tables&nbsp;To&nbsp;Tune）页上，点击&#8220;选择所有数据库<br>&#8221;（Select&nbsp;All&nbsp;Tables）按钮。点击&#8220;下一步&#8221;。此时，Index&nbsp;Tuning&nbsp;Wizard将试着<br>找出现有索引存在的问题以及解决办法，以改善数据库性能。这个过程将持续数分钟。&nbsp;<br><br>在完成分析之后，你将看见&#8220;索引建议&#8221;（Index&nbsp;Recommendations）页。如果Index&nbsp;<br>Tuning&nbsp;Wizard找到了可以改善性能的方法，它将把这些方法在本页面中罗列出来，并且<br>对可能产生的性能改进做出评估。一般来说，你可以安全地接受这些修改。点击&#8220;下一<br>步&#8221;继续。&nbsp;<br>在&#8220;完成索引调整向导&#8221;（Completing&nbsp;the&nbsp;Index&nbsp;Tuning&nbsp;Wizard）页上，点击&#8220;完成<br>&#8221;按钮关闭向导，然后在收到提示时点击&#8220;确定&#8221;按钮。另外，你可能还需要关闭SQL&nbsp;<br>Profiler。&nbsp;<br>&nbsp;<br><br>结论&nbsp;<br><br>系统管理员可以对以.NET&nbsp;Framework.为基础构建的程序性能进行深入的剖析和控制。例<br>如，&nbsp;ASP.NET便具有会话状态跟踪能力，可以对每个应用程序进行单独跟踪。这些功能<br>使得管理员可以调整一个应用程序的工作，使其满足他们的工作环境对性能、伸缩性和<br>可靠性的独特需要。本白皮书介绍了监视.NET&nbsp;Framework程序性能、模拟繁忙条件和配<br>置主要性能参数的方法。如果希望获得更多有关程序性能调整的信息，请访问以下地址<br>：&nbsp;<a  href="http://msdn.microsoft.com/library/en-us/dnduwon/html/d5dplyover.asp." target="_blank">http://msdn.microsoft.com/library/en-us/dnduwon/html/d5dplyover.asp.</a> <br></pre><img src ="http://www.cnitblog.com/stomic/aggbug/55192.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-08 17:46 <a href="http://www.cnitblog.com/stomic/archive/2009/03/08/55192.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何提高网页的效率</title><link>http://www.cnitblog.com/stomic/archive/2009/03/06/55145.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Fri, 06 Mar 2009 04:45:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/06/55145.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55145.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/06/55145.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55145.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55145.html</trackback:ping><description><![CDATA[<h4>网站最基本的东西是什么？</h4>
<p>网站最基本的东西是什么？<br>
——内容？SEO（搜索引擎优化）？UE（用户体验）？都不对！是速度！<br>
内容再丰富的网站，如果慢到无法访问也是毫无意义的； SEO做的再好的网站，如果搜索蜘蛛抓不到也是白搭； UE设计的再人性化的网站，如果用户连看都看不到也是空谈。<br>
所以网页的效率绝对是最值得关注的方面。如何才能提高一个网页的效率呢？Steve Souders(Steve Souders的资料<a  href="http://www.oreillynet.com/pub/au/2951" target="_blank">http://www.oreillynet.com/pub/au/2951</a>)提出的提高网页效率的14条准则，而这些准则也将是我们下篇中介绍到的YSlow工具的理论基础：<br>
</p>
<ul style="margin: 0px 2px 0px 15px; list-style-image: url(http://images.cnblogs.com/cnblogs_com/justinyoung/common/wedgits_red.gif);">
    <li>Make Fewer HTTP Requests
    </li>
    <li>Use a Content Delivery Network
    </li>
    <li>Add an Expires Header
    </li>
    <li>Gzip Components
    </li>
    <li>Put CSS at the Top
    </li>
    <li>Move Scripts to the Bottom
    </li>
    <li>Avoid CSS Expressions
    </li>
    <li>Make JavaScript and CSS External
    </li>
    <li>Reduce DNS Lookups
    </li>
    <li>Minify JavaScript
    </li>
    <li>Avoid Redirects
    </li>
    <li>Remove Duplicate Scripts
    </li>
    <li>Configure ETags
    </li>
    <li>Make Ajax Cacheable </li>
</ul>
这里我们将逐一的讲解这些准则,对其中开发者密切相关的准则我将详细讲解。小弟个人技术实在有限，错误和无知在所难免，还请高人指点。<br>
<p>&nbsp;</p>
<h4>第一条：Make Fewer HTTP Requests 尽可能的减少HTTP的Request请求数。</h4>
<p>80%的用户响应时间都是浪费在前端。而这些时间主要又是因为下载图片、样式表、JavaScript脚本、flash等文件造成的。减少这些资源文件的Request请求数将是提高网页显示效率的重点。<br>
这里好像有个矛盾，就是如果我减少了很多的图片，样式，脚本或者flash，那么网页岂不是光秃秃的，那多难看呢？其实这是一个误解。我们只是说尽量的减少，并没有说完全不能使用。减少这些文件的Request请求数，当然也有一些技巧和建议的：<br>
</p>
<h5>1：用一个大图片代替多个小图片。</h5>
这的确有点颠覆传统的思维了。以前我们一直以为多个小图片的下载速度之和会小于一个大图片的下载速度。但是现在利用httpwatch工具的对多个页面进行分析后的结果表明事实并不是这样。<br>
第一张图是一个大小为40528bytes的337*191px的大图片的分析结果。<br>
第二张图是一个大小为13883bytes的280*90px的小图片的分析结果。<br>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/webEfficiency07.jpg" title="点击查看大图" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/webEfficiency07.jpg" alt="点击查看大图" width="620" border="0" height="109"></a><br>
一个大小为40528bytes的337*191px的大图片的分析结果（点击图片可以查看完整大图片）</div>
<br>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/webEfficiency05.jpg" title="点击查看大图" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/webEfficiency05.jpg" alt="点击查看大图" longdesc="httpwatch" width="620" border="0" height="107"></a><br>
一个大小为13883bytes的280*90px的小图片的分析结果（点击图片可以查看完整大图片）</div>
第一张大图片花费时间为：<br>
Blocked：13.034s<br>
Send：0.001s<br>
Wait：0.163s<br>
Receive：4.596s<br>
TTFB：0.164s<br>
NetWork：4.760s<br>
功耗时：17.795s<br>
真正用于传输大文件花费的时间为Reveive时间，即4.596s，多数的时间是用来检索缓存和确定链接是否有效的Blocked时间，供花费13.034s，占总时间的73.2%。<br>
<br>
第二张小图片花费时间为：<br>
Blocked：16.274s<br>
Send：小于0.001s<br>
Wait：0.117s<br>
Receive：0.397s<br>
TTFB：0.118s<br>
NetWork：0.516s<br>
功耗时：16.790s<br>
真正用于传输文件的花费时间是Reveive时间，即0.397s，这的确要比刚才大文件的4.596s小很多。但是他的Blocked时间为16.274s，占总时间的97%。<br>
<br>
如果这些数据还不够说服你的话，让我们看看下面这张图。这里列出了某个网页中所有图片中的花费时间示意图。当然，里面的图片有大有小，规格不一。<br>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/webEfficiency08.jpg" title="点击查看大图" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/webEfficiency08.jpg" alt="httpwatch,杨正祎,Yes!B/S!" longdesc="httpwatch,杨正祎,Yes!B/S!" width="620" border="0" height="195"></a><br>
大约80%以上的时间是用来检索缓存和确定链接是否有效的Blocked时间。</div>
其中藏青色的为传输文件花费的Reveive时间，而前面白色的为检索缓存和确认链接是否有效的Blocked时间。铁一样的事实告诉我们：
<ul style="margin: 5px 2em; list-style-type: square;">
    <li>大文件和小文件下载所需时间的确是不同的，差异的绝对值不大。而且下载所需时间占总耗费时间比例很小。
    </li>
    <li>大约80%以上的时间是用来检索缓存和确定链接是否有效的Blocked时间。无论文件大小，这个时间的花费大致是相同的。而且所占总耗费时间的比例是极大的。
    </li>
    <li>一个100k的大图片总耗费时间绝对大于4个25k的小图片的总耗费时间。而且主要差别就是4个小图片的Blocked时间绝对大于1个大图片的Blocked时间。 </li>
</ul>
所以如果可能还是使用大图片来替代过多的琐碎的小图片吧。这也是为什么翻转门的效率要高于图片替换实现的滑动门的原因。<br>
但是，请注意：也不能用太大的单张图片，因为那样会影响到用户体验。例如个几兆的背景图片的使用绝对不是一个好主意。<br>
<h5>2：合并你的css文件。</h5>
<div class="floatRPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/hebin.jpg" alt="合并,合并示意图"></a><br>
图:合并与融合</div>
我以前犯了一个错误，你在看我《样式表的组织与规划》的系列文章中会知道。当时，我为了方便组织和规划样式表，将用于不同用途的样式表文件分离开来，形成
不同的css文件。然后在页面中根据需要引用多个css文件。根据&#8220;尽可能的减少HTTP的Request请求数&#8221;准则我们知道，那样的确是不合理的，因
为那样会产生更多的HTTP的Request请求数。从而降低网页的效率。所以，从提高网页效率的角度上而言，我们还是应该将所有的css写在同一个
css文件中。但是问题又来了。那么怎么来很好的组织和规划样式表呢？这的确是个矛盾。我现在的做法是采用两套版本。编辑版和发布版。编辑版仍然使用多个
css文件以便于规划和组织。而等到发布的时候，再将多个css文件合并到一个文件中去，从而达到减少HTTPRequest请求数的目的。<br>
<h5>3：合并你的javascript文件。</h5>
原因和处理方法同上，不再赘言。<br>
<p>&nbsp;</p>
<h4>第二条：Use a Content Delivery Network 使用CDN</h4>
<p>这个看上去好像很深奥的样子，但是只要结合中国的网络特色，这个便不难理解了。&#8220;北方服务器&#8221;、&#8220;南方服务器&#8221;、&#8220;电信服务器&#8221;、&#8220;网通服务器
&#8221;&#8230;&#8230;这些词听起来是那么熟悉和压抑。如果，一个北京的电信用户试图从广东的网通服务器上打开一个类似《壁纸合集》帖子的网页时，你就能很深刻的理解。<br>
鉴于这个不是我们开发人员力所能及的准则，所以这里也就不多言了。
</p>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/CDN.jpg" alt="CDN,南北服务器,电信网通,宽带互联" width="314" height="187"></a><br>
图:这个图也算有点中国特色了</div>
<p>&nbsp;</p>
<h4>第三条：Add an Expires Header 添加周期头</h4>
<p>这个也并非开发人员来控制，而是网站服务器管理员的职责。所以，如果作为开发人员的你不了解和明白也没有关系。还是把这个准则告诉公司的网站服务器管理员。</p>
<h4>第四条：Gzip Components 启用Gzip压缩</h4>
<p>这个大家应该比较熟悉。Gzip的思想就是把文件先在服务器端进行压缩，然后再传输。这对于体积较大的纯文字型的文件有特效。鉴于这也并非开发人员，而是网站服务器管理员的工作范畴，这里就不详细讲解了。如果你对此感兴趣，可以资讯贵公司的网站服务器管理人员。</p>
<h4>第五条：Put CSS at the Top 把CSS样式放在页面的上方。</h4>
<p>无论是HTML还是XHTML还是CSS都是解释型的语言，而非编译型的。所以CSS到上方的话，那么浏览器解析结构的时候，就已经可以对页面进行
渲染。这样就不会出现，页面结构光秃秃的先出来，然后CSS渲染，页面又突然华丽起来，这样太具有&#8220;戏剧性&#8221;的页面浏览体验了。</p>
<h4>第六条：Move Scripts to the Bottom 将脚本放在底部</h4>
<p>原因同第五条一样。只是脚本一般是用来于用户交互的。所以如果页面还没有出来，用户连页面都不知道什么样子，那谈交互简直就是扯谈。所以，脚本和CSS正好相反，脚本应该放在页面的底部。</p>
<h4>第七条：Avoid CSS Expressions 避免使用CSS中的Expressions</h4>
<p>
</p>
<div class="floatRPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/Expressions.jpg" alt="if语句,expression,判断语句示意图" width="246" height="231"></a><br>
图:CSS中的Expressions其实也是一种if判断</div>
首先有必要先说明一下CSS Expressions是什么一个东西。其实它就像其它语言中的if&#8230;&#8230;else&#8230;&#8230;语句。这样在CSS中就可以进行简单的逻辑判断了。举个简单的例子——<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 410px; background-color: #eeeeee;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">style</span><span style="color: #0000ff;">&gt;</span><span style="color: #800000; background-color: #f5f5f5;"><br>
input</span><span style="color: #000000; background-color: #f5f5f5;">{</span><span style="color: #ff0000; background-color: #f5f5f5;">background-color</span><span style="color: #000000; background-color: #f5f5f5;">:</span><span style="color: #0000ff; background-color: #f5f5f5;">expression((this.readOnly&nbsp;&amp;&amp;&nbsp;this.readOnly==true)?"#0000ff":"#ff0000")</span><span style="color: #000000; background-color: #f5f5f5;">}</span><span style="color: #800000; background-color: #f5f5f5;"><br>
</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">style</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>
</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">INPUT&nbsp;</span><span style="color: #ff0000;">TYPE</span><span style="color: #0000ff;">="text"</span><span style="color: #ff0000;">&nbsp;NAME</span><span style="color: #0000ff;">=""</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>
</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">INPUT&nbsp;</span><span style="color: #ff0000;">TYPE</span><span style="color: #0000ff;">="text"</span><span style="color: #ff0000;">&nbsp;NAME</span><span style="color: #0000ff;">=""</span><span style="color: #ff0000;">&nbsp;readonly</span><span style="color: #0000ff;">="true"</span><span style="color: #0000ff;">&gt;</span></div>
这样css就可以根结一些情况分别使用不同的样式了。如果你对这个感兴趣可以到我的博客上阅读相关的文章—— <a  href="http://www.google.cn/search?q=expression&amp;ie=UTF-8&amp;oe=GB2312&amp;hl=zh-CN&amp;domains=http://www.cnblogs.com/JustinYoung/&amp;sitesearch=http://www.cnblogs.com/JustinYoung/" title="CSS中的expression" target="_blank">《CSS中的expression系列文章》</a>。但是CSS中Expressions 的代价却是极高的。当你的页面需要根据判断来渲染效果的元素很多的时候，那么你的浏览器将长期处于假死状态，从而给用户带来极差的用户体验。<br>
<p>&nbsp;</p>
<h4>第八条：Make JavaScript and CSS External 将javascript和css独立成外部文件</h4>
<p>这一条好像和第一条有点矛盾。的确，如果从HTTP的request请求数来讲的话，这样做的确是降低了效率。但是之所以这么做，是因为另外一个重
要的考虑因素——缓存。因为外部的引用文件会被浏览器缓存，所以如果javascript和css体积较大的时候，我们将它们独立成外部文件。这样当用户
只要浏览一次以后，这些体积较大的js和css文件就能被缓存起来，从而极高地提高用户再次访问时的效率。 </p>
<h4>第九条：Reduce DNS Lookups&nbsp; 减少DNS查询</h4>
<p>DNS域名解析系统。大家都知道我们之所以能记住那么多的网址，是因为我们记住的都是单词，而非http://202.153.125.45这样的
东西，而帮我们把那些单词和202.153.125.45这样的ip地址联系起来的就是DNS。那这一条对我们到底有什么真正意义上的指导意义呢？其实有
两条：<br>
1：如果不是必须，请不要把网站放到两台服务器上。<br>
2：网页中的图片、css文件、js文件、flash文件等等，不要太多的分散在不同的网络空间中。这就是为什么那种只发一个网站中的壁纸图片的帖子，要比壁纸图片来源于不同网站的帖子显示要快得多的原因。</p>
<h4>第十条：Minify JavaScript and CSS&nbsp; 减少JavaScript和CSS文件的体积</h4>
<p>这点很好理解。在你的最终发布版本中把没有必要的空行、空格和注释全部去掉。显然手工去处理效率太低，好在网上到处都是用于压缩这些东西的工具。压缩JavaScript代码体积的工具随处可见，我便不再列举了，这里我只提供一个用于压缩css代码体积的在线工具网站——<a  href="http://www.cssdrive.com/index.php/main/csscompressor" target="_blank">http://www.cssdrive.com/index.php/main/csscompressor</a><br>
它提供了多种压缩方式，可以适应多种要求。 </p>
<h4>第十一条：Avoid Redirects 避免跳转</h4>
<p>我只从网页开发人员的角度来解读此条。那么我们可以解读到什么东西呢？2点——<br>
1：&#8220;此域名已过期，5秒钟以后，页面将跳转到http://www.xxxxxx.com/index.html页面&#8221;，这句话看起来的确很熟悉。但是，我就奇怪了，为什么不直接链接到那个页面呢？<br>
2：一些链接地址请更明确的写出来。例如:将<a  href="http://justinyoung.cnblogs.com/" target="_blank">http://justinyoung.cnblogs.com/</a> 写成<a  href="http://justinyoung.cnblogs.com/" target="_blank">http://justinyoung.cnblogs.com</a> （注意最后面一个&#8220;/&#8221;符号）。的确，这两个网址都能访问到我的博客，但是，事实上，它们是有区别的。<a  href="http://justinyoung.cnblogs.com/" target="_blank">http://justinyoung.cnblogs.com</a> 的结果是个301响应，它会被重新指向<a  href="http://justinyoung.cnblogs.com/" target="_blank">http://justinyoung.cnblogs.com/</a> 。但是显然，中间多浪费了一些时间。</p>
<h4>第十二条 Remove Duplicate Scripts 移除重复的脚本</h4>
<div class="floatLPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/noRepeat.jpg" alt="对重复说不" width="120" height="90"></a><br>
图:对重复说&#8220;不！&#8221;</div>
<p>这个准则的道理很浅显，但是真正在工作中，很多人却因为&#8220;项目时间紧&#8221;、&#8220;太累了&#8221;、&#8220;初期没有规划好&#8221;&#8230;&#8230;这样的理由搪塞过去了。你，的确可以找很多的理由不去处理这些多余重复的脚本代码，如果你的网站不需要更高的效率和后期维护的话。<br>
也正是这点，我提醒大家一些，一些javascript框架、javascript包一定要慎用。至少要问一下：用了这个js kit 到底给我们多少方便，提高了多少工作效率。然后，再与它因为多余的、重复的代码带来的负面效果比较一下。</p>
<h4>第十三条：Configure ETags 配置你的实体标签</h4>
<p>首先来讲讲什么是Etag吧。Etag（Entity tags
）实体标签。这个tag和你在网上经常看到的标签云那种tag有点区别。这个Etag不是给用户用的，而是给浏览器缓存用的。Etag是服务器告诉浏览器
缓存，缓存中的内容是否已经发生变化的一种机制。通过Etag，浏览器就可以知道现在的缓存中的内容是不是最新的，需不需要重新从服务器上重新下载。这和
&#8220;Last-Modified&#8221;的概念有点类似。很遗憾作为网页开发人员对此无能为力。他依然是网站服务器人员的工作范畴。如果，你对此有兴趣，可以咨询
贵公司的网站服务器管理员。</p>
<h4>第十四条：Make Ajax Cacheable 上面的准则也适用Ajax</h4>
<div class="floatRPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计" target="_blank"><img  src="http://images.cnblogs.com/cnblogs_com/justinyoung/common/ajax.jpg" alt="Ajax" width="148" height="78"></a><br>
图:Ajax的使用要恰当</div>
<p>现在的Ajax好像有点被神话了，好像网页只要Ajax了，那么就不存在效率问题了。其实这是一种误解。拙劣的使用Ajax不会让你的网页效率更高，反而会降低你的网页效率。Ajax的确是个好东西，但是请不要过分的神话它。使用Ajax的时候也要考虑上面的那些准则。</p>
<h4>后记：</h4>
<p>当然，上面的这些也只是供你参考的理论上的准则。具体的情况还是要具体的去对待。理论和准则只是用来指导现实工作的，却是万万不可死记硬套。</p>
<p>网站最重要的东西是什么？<br>
——内容？SEO（搜索引擎优化）？UE（用户体验）？都不对！是速度！<br>
内容再丰富的网站，如果慢到无法访问也是毫无意义的； SEO做的再好的网站，如果搜索蜘蛛抓不到也是白搭(页面效率和搜索蜘蛛之间的关系，需要进一步的确认，此为和上篇保持统一)； UE设计的再人性化的网站，如果用户连看都看不到也是空谈。
</p>
<p>所以网页的效率绝对是最值得关注的方面。虽然我们在<a  href="http://www.cnblogs.com/JustinYoung/archive/2007/11/20/speeding-up-web-site-14rule.html" title="《如何提高网页的效率（上篇）——提高网页效率的14条准则》" target="_blank"> 《如何提高网页的效率（上篇）——提高网页效率的14条准则》</a>提
到了如何提高网页效率的14条准则，但是如何知道我们现在的网页的效率到底如何？到底处于怎样一个级别？又有哪些方面做的不够好，需要改进呢？也许，你会
说，问一下用户不就知道了吗？但是相比感性比例占据太大的用户感受而言，理性的工具和数据更具有说服力。本篇就将向你介绍一款评测网页效率的工具——
YSlow（why slow，这个名字起的太好了）。
</p>
<div class="floatRPic"><a  href="http://justinyoung.cnblogs.com/" title="yslow,yslow logo" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslowlogo.png" alt="yslow,yslow Logo"></a><br>
yslow</div>
<p><a  href="http://developer.yahoo.com/yslow/" title="YSlow" target="_blank">YSlow</a>是由<a  href="http://developer.yahoo.com/" title="Yahoo开发者团队" target="_blank">Yahoo开发者团队</a>发布的一款基于Firebug的插件。而<a  href="https://addons.mozilla.org/en-US/firefox/addon/5369" title="Firebug" target="_blank">Firebug</a> 又是一款基于FireFox的插件。所以说YSlow是一款基于FireFox插件的插件。虽然有点绕，但是最终说明的问题是：
</p>
<ul style="margin: 10px 0px 0px 15px; list-style-image: url(http://images.cnblogs.com/cnblogs_com/justinyoung/common/wedgits_red.gif);">
    <li>很遗憾，微软的IE系列浏览器不能使用YSlow。
    </li>
    <li>YSlow只能使用在FireFox浏览器上。
    </li>
    <li>如果要想使用YSlow，那么你必须先安装FireFox。
    </li>
    <li>如果要想使用YSlow，那么你就要安装FireFox上的Firebug插件。 </li>
</ul>
<p>这看上去好像有点令人沮丧，但是事实上它并不像想象中的那么麻烦，只要按照下面的步骤你将能很快的使用YSlow：
</p>
<ol style="font-size: 10pt; margin-left: 2em;">
    <li>到<a  href="http://www.mozilla.net.cn/firefox/">http://www.mozilla.net.cn/firefox/</a><a  href="http://www.mozilla.net.cn/firefox/" target="_blank"><img  src="http://images.cnblogs.com/cnblogs_com/justinyoung/common/outLink.gif" alt="在新窗口打开此链接"></a> 下载最新版的FireFox，并安装它。当然如果你已经安装了FireFox可以跳过此步。
    </li>
    <li>到<a  href="https://addons.mozilla.org/en-US/firefox/addon/1843/">https://addons.mozilla.org/en-US/firefox/addon/1843/</a><a  href="https://addons.mozilla.org/en-US/firefox/addon/1843/" target="_blank"><img  src="http://images.cnblogs.com/cnblogs_com/justinyoung/common/outLink.gif" alt="在新窗口打开此链接"></a> 下载最新版的Firebug，并安装它。当然如果你已经安装了Firebug可以跳过此步。
    </li>
    <li>到<a  href="https://addons.mozilla.org/en-US/firefox/addon/5369/">https://addons.mozilla.org/en-US/firefox/addon/5369/</a><a  href="https://addons.mozilla.org/en-US/firefox/addon/5369/" target="_blank"><img  src="http://images.cnblogs.com/cnblogs_com/justinyoung/common/outLink.gif" alt="在新窗口打开此链接"></a> 下载最新版的YSlow，并安装它。当然如果你已经安装了YSlow可以跳过此步。 </li>
</ol>
<p>
</p>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow01.jpg" alt="firefox,firebug,yslow" width="514" height="355"></a><br>
图2：在菜单中先打开Firebug插件</div>
这时候打开FireFox，你将在【工具】菜单中看到【firebug】（如图2）。打开firebug，然后在firebug中点击YSlow菜单，便看进入YSlow的主界面（如图3）。<br>
<div class="floatMPic"><a  href="http://www.cnblogs.com/JustinYoung/archive/2007/11/28/pic/02.jpg" title="点击小图查看完整大图" target="_blank"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow02.jpg" alt="点击小图查看完整大图" width="620" height="248"></a><br>
图3：在菜单中先打开Firebug插件(点击小图查看完整大图)</div>
<h4>点击【Performace】菜单</h4>
<p>YSlow便开始分析此页的效率，并从13个最影响网页效率的方面给出评估（如图4）。
</p>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow03.jpg" alt="firefox,firebug,yslow"></a><br>
图4：YSlow给出的本页面效率评估</div>
<p>可以看出来，YSlow评估的依据就是我们在<a  href="http://www.cnblogs.com/JustinYoung/archive/2007/11/20/speeding-up-web-site-14rule.html" title="《如何提高网页的效率（上篇）——提高网页效率的14条准则》" target="_blank"> 《如何提高网页的效率（上篇）——提高网页效率的14条准则》</a>中提到的前面13条。前面蓝色的字母表示这一条准则的得分。A最高。点击右面的三角形可以得到更多的信息和建议，有些信息里面还有&#8220;放大镜&#8221; 图标，点击也将展示更为详细的信息和建议。（如图5所示）
</p>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow09.jpg" alt="firefox,firebug,yslow"></a><br>
图5：YSlow可以给出每条准则的详细评估信息和建议</div>
<h4>点击【Stats】菜单</h4>
<p>这个视图会告诉你页面的总体统计信息。包括页面大小、css样式表大小、脚本文件大小、总体图片大小、flash文件大小和css中用到的图片文件大小。还会告诉你，哪些东西被缓存了，缓存了多少等等。
</p>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow10.jpg" alt="firefox,firebug,yslow"></a><br>
图6：【Stats】视图信息</div>
<h4>点击【Components】菜单</h4>
<p>这个视图是一个页面所有部件的信息列表。从中我们可以得知每个部件的各种详细信息。如：类型、URL、Expires数据、状态、大小、读取时间、ETag信息等等。通过对这个列表的分析，我们就可以知道到底是什么东西最耗费我们的资源，从而有针对性的进行优化。
</p>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow11.jpg" title="firefox,firebug,yslow"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow11.jpg" alt="firefox,firebug,yslow" width="620" height="337"></a><br>
图7：【Components】视图信息，点击&#8220;放大镜&#8221;图标我们可以知道更详细的信息（点击小图查看完整大图）</div>
<h4>点击【Tools】菜单</h4>
<p>【Tools】菜单包含4个子菜单，就是4个实用工具。【JSLine】工具会生成JSLine报表，报表是对本网页中JS脚本的分析报告，包含错
误和建议。【ALL JS】工具，将生成本页面所有脚本代码便于阅读和打印的报表页面。【ALL CSS】工具，将生成本页面
所有CSS样式表代码便于阅读和打印的报表页面。【Printable
View】将【Performance】和【Stats】视图中的信息生成一份更适合阅读和打印的报表页面。
</p>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow12.jpg" alt="firefox,firebug,yslow"></a><br>
图8：【Tools】菜单，包含了4个子菜单</div>
<h4>点击【Help】菜单</h4>
<p>【Help】主要是些常用的帮助途径的入口。从这里你可以很方面的访问YSlow的官方网络和博客。如果你还对YSlow的使用有什么疑惑的话，那么在这里你将获得满意的解答。
</p>
<div class="floatMPic"><a  href="http://justinyoung.cnblogs.com/" title="web标准设计"><img  src="http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/yslow13.jpg" alt="firefox,firebug,yslow"></a><br>
图8：【Help】菜单是些常用的帮助入口</div>
<h4>后记</h4>
<p>&#8220;工欲善其事，必先厉其器！&#8221;好的工具的确能很大的提高我们的工作效率。但是&#8220;阿斗&#8221;就算手里拿着&#8220;方天画戟&#8221;，估计也没有几个人怕他。好的工具是一方面，但是更重要的还是提高我们自身的知识水平。就如同这款YSlow，如果没有<a  href="http://www.cnblogs.com/JustinYoung/archive/2007/11/20/speeding-up-web-site-14rule.html" title="《如何提高网页的效率（上篇）——提高网页效率的14条准则》" target="_blank"> 《如何提高网页的效率（上篇）——提高网页效率的14条准则》</a>中的理论知识，工具提供的信息我们看到的可能只是表面，就算看懂了数据，我们也很难知道对应的手段和措施。壮汉拿厉斧，这样伐木才能又快又轻松。 </p><img src ="http://www.cnitblog.com/stomic/aggbug/55145.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-06 12:45 <a href="http://www.cnitblog.com/stomic/archive/2009/03/06/55145.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LoadRunner函数中文翻译系列之二--Check</title><link>http://www.cnitblog.com/stomic/archive/2009/03/03/55073.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Tue, 03 Mar 2009 08:05:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/03/55073.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55073.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/03/55073.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55073.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55073.html</trackback:ping><description><![CDATA[<p class=content><strong>web_find</strong><br><br>　语法：<br>　int web_find (const char *StepName, &lt;Attributes and Specifications list&gt;, char *searchstring, LAST ); </p>
<p class=content>参数：<br>　1、StepName：步骤名称，在Tree视图中出现。</p>
<p class=content>2、Attributes and Specifications list：</p>
<p class=content>支持的属性有： </p>
<p class=content>Frame：在多Frame的情况下，定义要查找Frame的范围。</p>
<p class=content>Expect：定义在什么情况下函数检查成功：找到了指定的搜索标准或者没有找到。例如说，可以检查指定的错误信息是否出现在web页面中。合法的值有2个：found和notfound。默认值是&#8220;found&#8221;。</p>
<p class=content>Matchcase：指定搜索是否区分大小写。</p>
<p class=content>Repeat：指定当第一次发现要查找的字符串时，搜索是否继续。当一个web页面中包含多个被查找的字符串时，此参数是非常有用的。合法的值有2个：yes，no。默认值是&#8220;yes&#8221;。</p>
<p class=content>Report：指定在什么情况下，VuGen在执行日志中显示此函数的检查结果。合法的值有：success，failure，always。默认值是&#8220;always&#8221;。</p>
<p class=content>Onfailure：此参数决定在函数检查失败后，Vuser是否中断。参数值是abort。如果指定了Onfailure=abort,当函数检查失败时，不论在运行时设置中的error-handling是什么，脚本都会中断。</p>
<p class=content>如果没有指定Onfailure=abort,那么运行时设置中error-handling将会起作用。</p>
<p class=content>支持的特性有：RightOf, LeftOf （不支持7.x及更高版本）。</p>
<p class=content>RightOf：要查找的字符串右边的内容。</p>
<p class=content>LeftOf：要查找的字符串左边的内容。</p>
<p class=content>3、Searchstring：需要查找的字符串，格式为&#8220;What=stringxyz&#8221;。此搜索不区分大小写。</p>
<p class=content>4、LAST：属性列表结束符。</p>
<p class=content>返回值<br>　整型。 成功时返回LR_PASS(0)，失败时返回LR_FAIL (1)。</p>
<p class=content>说明<br>　此函数的作用是在HTML页面中查找指定的字符串。</p>
<p class=content>此函数只能在基于HTML录制的脚本中使用。当指定的HTML请求全部完成以后，开始执行搜索过程，比web_reg_find要慢。</p>
<p class=content>web_find函数在C语言的脚本中已经被web_reg_find所替代，web_reg_find运行速度比较快，而且在HTML-based和URL-based的录制方式中都可以使用。 在C语言脚本中，web_find是向后兼容的。Java和Visual Basic脚本中不再支持它。</p>
<p class=content>运行在HTTP模式下的WAP用户都和运行在WSP回放模式下的WAP用户都不支持此函数。</p>
<p class=content><strong>web_global_verification</strong><br><br>　语法：<br>　int web_global_verification (&lt;List of Attributes&gt;, LAST )；</p>
<p class=content>参数：<br>　List of Attributes：</p>
<p class=content>1、Text：此属性是一个非空的，以NULL结尾的字符串，表示要查找的内容。语法是&#8221;Text=string&#8221;。还可以使用text flags自定义字符串。</p>
<p class=content>2、TextPfx：没有指定Text的情况下使用此属性。要查找的字符串的前缀。语法是&#8221; TextPfx =string&#8221;。还可以使用text flags自定义字符串。</p>
<p class=content>3、TextSfx：没有指定Text的情况下使用此属性。要查找的字符串的后缀。语法是&#8221; TextSfx =string&#8221;。还可以使用text flags自定义字符串。</p>
<p class=content>4、Search：可选项，在哪里查找字符串。可选的值是：Headers，Body，NORESOURCE或All。默认值是NORESOURCE。语法是&#8220;Search=value&#8221;。</p>
<p class=content>5、Fail：当字符串找不到时的处理选项：Found （默认值）或NotFound。Found表示当找到对应的字符串时发生了错误（例如&#8220;Error&#8221;）。NotFound表示当找不到字符串时发生了错误。语法是&#8220;Fail=value&#8220;。</p>
<p class=content>6、ID：在日志文件中标识当前函数。</p>
<p class=content>LAST：属性列表结束符。</p>
<p class=content>注：text flags：/IC表示忽略大小写；/BIN表示指定的是二进制数据。</p>
<p class=content>返回值<br>　整型。 成功时返回LR_PASS(0)，失败时返回LR_FAIL (1)。</p>
<p class=content>说明<br>　web_global_verification属于注册函数，注册一个在web页面中搜索文本字符串的请求，与web_reg_find只在下一个 Action函数中执行搜索不同的是，它是在之后所有的Action类函数中执行搜索的。可以搜索页面的body，headers，html代码或者是整个页面。</p>
<p class=content>在检测一些应用程序级别（不通过http状态码来表现）的错误时，web_global_verification是非常有用的。如果要定位通过HTTP状态码表现的错误时，使用web_get_int_property。</p>
<p class=content>查找范围：all：这个HTML页面；Headers：页面的头；body：页面的体，包含所有的资源但不包含头；NORESOURCE（默认选项）：仅仅包含页面的体，把包括头和资源。</p>
<p class=content>如果不知道要查找的精确的文本，或者要查找的多个文本不是完全相同的,可以使用前缀和后缀来表示。这时需要用到TextPfx和TextSfx属性。这2个属性必须同时指定，一旦指定了其中一个，就不能指定Text属性了。</p>
<p class=content>注意：web_global_verification在WAP协议下不能运行。</p>
<p class=content><strong>web_image_check</strong><br><br>　语法：<br>　int web_image_check(const char *CheckName, &lt;List of Attributes&gt;, &lt;"Alt=alt"|| "Src=src"&gt;, LAST ); </p>
<p class=content>参数：<br>　1、CheckName：名称，在Tree视图中出现。</p>
<p class=content>2、List of Attributes：</p>
<p class=content>支持的属性有：Frame（在多Frame的情况下，定义要查找Frame的范围）。</p>
<p class=content>支持的选项有：expect, matchcase, repeat, report, onfailure。</p>
<p class=content>Tip：选项跟属性的区别，大部分选项都只允许设置预定义的值，其他的值都是无效的。</p>
<p class=content>3、Alt：检查图象的ALT标记。不允许空值。</p>
<p class=content>4、Src：检查图象的SRC标记。不允许空值。</p>
<p class=content>5、LAST：参数列表结束的指示符。</p>
<p class=content>返回值<br>　整型。 </p>
<p class=content>说明<br>　web_image_check检查指定的图象是否在HTML页面中出现。 </p>
<p class=content>Alt或者Src两者必须有一个在参数列表中出现。如果两项都通过，那么检查成功。 </p>
<p class=content>此函数仅仅支持基于HTML的脚本。<br><br><strong>　web_reg_add_cookie</strong><br><br>　语法：<br>　int web_reg_add_cookie(const char * cookie, const char * searchstring, LAST ); </p>
<p class=content>参数：<br>　1、Cookie：定义需要增加或修改的Cookie。</p>
<p class=content>Cookie的参数格式为：&lt;name&gt;=VALUE; (required)；domain=DOMAIN_NAME;(required)；expires=DATE；path=PATH；(default path is "/")；secure。</p>
<p class=content>此参数中的cookie元素和HTTP响应头中的Set-Cookie是相同的。例如&#8220;Session=1234；domain=sanditon.com&#8221;，在这里，&#8220;Session&#8221;是cookie的名称。</p>
<p class=content>2、Searchstring：要查找的文本字符串。字符串不能为空，以null结尾。格式为&#8220;Text=string&#8221;。</p>
<p class=content>3、LAST：属性列表的结束符。</p>
<p class=content>返回值<br>　整型。 成功时返回LR_PASS(0)，失败时返回LR_FAIL (1)。</p>
<p class=content>说明<br>　web_reg_add_cookie是注册类型的函数。它首先注册一个搜索文本字符串的请求。检查动作在后续的Action函数之后进行。如果字符串被找到，就添加到cookie中。</p>
<p class=content>需要注意，尽管web_reg_add_cookie在功能上跟HTTP Set_Cookie头相似，它们还是有个明显的区别。 根据HTTP标准，domain属性在Set-Cookie头中是可选的。如果没有指定，默认的domain的值是产生cookie的服务器的host name。当使用web_reg_add_cookie函数时，服务器的hostname对于压力测试的机器来说是不可用的，所以domain属性是必选项。 </p>
<p class=content>此函数在HTML-based 和URL-based的脚本中都可以使用。（参照录制选项的录制标签页）。此函数是在服务器内容到达客户端之前注册搜索请求的，所以当所请求的内容一到就会执行搜索操作，脚本会比较高性。 </p>
<p class=content>web_reg_add_cookie是用户手动添加的，无法录制。</p>
<p class=content><strong>web_reg_find</strong><br><br>　语法：<br>　int web_reg_find (const char *attribute_list, LAST); </p>
<p class=content>参数：<br>　1、attribute_list：</p>
<p class=content>通过Name=Value对来传递参数。例如&#8220;Text=string&#8221;。Text，TextPfx，TextSfx三个必须有一个出现。其他的属性是可选的。</p>
<p class=content>a) Text：要搜索的字符串，字符串必须非空，以NULL结尾。可以使用text flags自定义搜索字符串。</p>
<p class=content>b) TextPfx：要搜索的字符串的直接前缀。</p>
<p class=content>c) TextSfx：要搜索的字符串的直接后缀。</p>
<p class=content>d) Search：搜索的范围。可选的值是：Headers 、Body（在请求体中搜索）、Noresource (仅仅在HTML请求体中搜索，不包括头和资源)、ALL （在请求体、头和资源中搜索），默认值是&#8220;BODY&#8221;。</p>
<p class=content>e) SaveCount：匹配的个数。</p>
<p class=content>f) Fail：设置函数检查在什么状态下失败。</p>
<p class=content>g) ID：日志文件中标识此函数的一个字符串。</p>
<p class=content>h) RelFrameId：相关联的FrameId。注意：此参数在GUI级别的脚本中不受支持。</p>
<p class=content>2、LAST：属性列表结束的标记符。</p>
<p class=content>返回值<br>　整型。 成功时返回LR_PASS(0)，失败时返回LR_FAIL (1)。</p>
<p class=content>说明<br>　web_reg_find属于注册函数，注册一个在web页面中搜索文本字符串的请求，在接下来的Action（象web_url）类函数中执行搜索。 </p>
<p class=content>通过查找期望的字符是否存在来验证是否返回了期望的页面。例如，通过查找&#8220;Welcome&#8221;来检查主页是否完全打开了。也可以查找&#8220;Error&#8221;检查浏览器是否发生错误。还可以使用此函数注册一个请求来统计特定字符串出现的次数。</p>
<p class=content>如果检查失败，在接下来的Action类的函数中会报告错误。此函数仅仅注册请求，并不执行。函数的返回值只表明注册是否成功，并不表示检查的结果。</p>
<p class=content>此函数不仅能够查找text，还能查找到围绕着text的strings。不要同时指定text和前缀后缀。 </p>
<p class=content>Fail，处理选项，可以是&#8220;Found或&#8220;NotFound&#8221;。默认是&#8220;NotFound&#8221;。 </p>
<p class=content>&#8220;Fail=Found&#8221; 指示当对应的字符找到时，函数检查失败。例如，查找单词&#8220;Error&#8221;，如果找到了，说名web请求没有成功，你想把函数检查设置为失败。</p>
<p class=content>&#8220;Fail=NotFound&#8221;指示当对应的字符找不到时，函数检查失败。如果查找的是web请求成功时出现的字符串时，需要使用NotFound。</p>
<p class=content>SaveCount参数指示保存到参数中的匹配的字符串的个数。使用这个属性，需要指定&#8220;SaveCount=param&#8221;。检查操作被执行后，param 的值是null结尾的数字类型的值。 </p>
<p class=content>如果指定了SaveCount，且没有使用Fail参数，检查不会失败，无论需要查找的字符串是否找到。通过检查SaveCount的值确定字符串是否被找到。 如果param是0，说明没有找到对应的字符串。</p>
<p class=content>如果同时指定了SaveCount和Fail，指定的错误处理选项和SaveCount协同工作。 handling option specified works together with the SaveCount. Thus,如果指定了SaveCount且指定了&#8220;Fail=NotFound&#8221; ，但是字符串被找到，SaveCount被赋值为字符串出现的次数，检查成功。如果字符串找不到，SaveCount被赋值为0，检查失败（注意，参数的0值只在运行时设置中Continue on error 选中时才有意义）。</p>
<p class=content>此函数在HTML-based和URL-based的脚本中都可以使用。此函数是在所请求内容到达之前注册搜索请求的，所以当所请求内容一到达后就会执行搜索，产生的脚本比较高效。</p>
<img src ="http://www.cnitblog.com/stomic/aggbug/55073.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-03 16:05 <a href="http://www.cnitblog.com/stomic/archive/2009/03/03/55073.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LoadRunner HTML录制模式与URL录制模式比较</title><link>http://www.cnitblog.com/stomic/archive/2009/03/02/55026.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Mon, 02 Mar 2009 03:51:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/02/55026.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/55026.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/02/55026.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/55026.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/55026.html</trackback:ping><description><![CDATA[在跟使用Loadrunner工具使用者交流的过程中，经常有人提到这个问题，基于HTML（HyperText Markup
Language 超文本置标语言）模式录制与基于URL（Uniform Resource
Locator的缩写，统一资源定位符，也被称为网页地址，是因特网上标准的资源的地址。）录制模式到底有什么不同？为什么通常情况下我们都会去选择使用
URL模式去录制我们的业务脚本？所以在这里我把我知道的东西写出来跟同行分享和交流：
<p>　　HTML是一种高级别的录制模式，这种模式是基于&#8220;浏览器&#8221;或者说是&#8220;内容敏感&#8221;的。这种录制选项是让浏览器去决定在回放下载HTML资源，哪些页面资源（比如图片或者Flash内容）是需要被下载。</p>
<p>　　URL是一种低级别的录制模式，这种录制选项不允许浏览器去确定哪些页面资源（比如图片或者Flash内容）是需要下载的。每项资源在录制回话的过程中都被录制到脚本中。这种级别录制模式同时也会录制<a  href="javascript:;" onclick="javascript:tagshow(event, '%c6%e4%cb%fb');" target="_self"><u><strong>其他</strong></u></a>任何隐藏的对象，比如session ID（也就是会话ID）信息，包括发给服务端和从服务端收到的session ID信息。</p>
<p>
脚本方面的不同，HTML级别录制模式将生成的是web_submit_form
语句来提交终端用户可以看见或者修改的信息。当基于HTML模式在提交窗体时遇到错误，你可以选择URL模式去录制任何从服务端发送过来的请求和资源。而
URL基本录制模式将生成的是web_submit_data语句，这些语句记录的是所有通过浏览器实际发送给服务端的信息。值得注意的是URL录制模式
会录制那些HTML模式没有能录制到隐藏信息。通常情况下，隐藏信息里面会包含session ID信息。</p>
写到这里，熟悉的人可能应该明白为什么在通常的情况下，我们选择URL模式去录制我们基于<a  href="javascript:;" onclick="javascript:tagshow(event, 'web');" target="_self"><u><strong>Web</strong></u></a>（HTTP/HTML）
协议的脚本，概括的说就是现在的应用（或者说将来的应用）为了安全性，都会包含像session
ID、token等动态信息。简单的说就是每一访问，服务端都会给客户端发送一个描述会话的session信息，而session
ID使用的是动态的生成技术。如果要是脚本能够正常回放，通常需要把这个动态的信息保存下来，这个需要使用到correlation
技术（也就是关联技术）。在以后我会在我的博客里面继续写我对关联的理解（包括自动关联、手工关联、规则等实用技术）。<img src ="http://www.cnitblog.com/stomic/aggbug/55026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-02 11:51 <a href="http://www.cnitblog.com/stomic/archive/2009/03/02/55026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在LoadRunner 脚本中使用关联</title><link>http://www.cnitblog.com/stomic/archive/2009/03/02/54971.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Mon, 02 Mar 2009 03:01:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/02/54971.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/54971.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/02/54971.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/54971.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/54971.html</trackback:ping><description><![CDATA[今天我将解释 LoadRunner 中关联的概念及其使用方法。我认为关联是 LoadRunner 中一个非常关键的概念。对于任何测试工程师而言，如果他想成为 LoadRunner 专家或是宗师，那他必须非常了解何谓关联。
<p><clk>&nbsp;实战举例： 我为某个<nobr id="clickeyekey0" style="border-bottom: 1px dotted #6600ff; text-decoration: underline; color: #6600ff; background-color: transparent;" onclick="'kwC(event,0,"")'" oncontextmenu="return false" onmouseover="kwE(event,0, this)" onmouseout="kwL(event,this)" onmousemove="kwM(0)">网络</nobr></clk><a  href="http://www.qqread.com/network/server/index.html" target="_blank">服务器</a>录制了一段 LoadRunner 脚本。脚本中包含两个特殊的域：时标（timestamp）和校验和（checksum）:</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_1.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_1.jpg" alt="在LoadRunner 脚本中使用关联（图一）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每当一个客户端网络浏览器连接到服务器，服务器就会获得一个当时的时标，再计算出校验和返回至客户端。这两个域是用来确认一次即时的会话。换句话说，一组时标 + 校验和就是会话 ID。以下就是这种交互的图解：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_2.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_2.jpg" alt="在LoadRunner 脚本中使用关联（图二）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 问题在哪里呢？让我们再回放一次录制的脚本。 当执行已录制的脚本时，出现了问题。网络服务器用当前时间检验客户端发来的时标。如果客户端的日期是过期的或错误的，服务器就会返回一个错误的信息：参数&#8220;校验和&#8221;未找到或显示为无效值。 此次交互的图解：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_3.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_3.jpg" alt="在LoadRunner 脚本中使用关联（图三）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 客户端不能再次使用旧的（即硬编码）的值作为时标和校验和。而必须使用新的日期。所以，LR 脚本应该运行服务器返回的动态数据，而非硬代码。使用关联就能做到这一点：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_4.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_4.jpg" alt="在LoadRunner 脚本中使用关联（图四）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p>&nbsp;&nbsp;&nbsp; 关联的定义：关联就是捕获服务器发送给客户端的动态值。 实现关联的方法：</p>
<p>1、自动</p>
<p>2、手动</p>
<p>自动关联会在后文中讲到。但是至今为止，我敢说自动关联并不是最好的解决方法。因为有些时候自动关联会失效，或者错误关联。 一个真正
LoadRunner 工程师会选择使用手动关联。所以说这是&#8220;必备&#8221;的学问！好吧，让我们来开始探究手动关联。 手动关联的使用法则如下：
找到一个需要捕获的动态值。</p>
<p>1) 找到服务器包含该动态值的响应。</p>
<p>2) 捕获动态值。使用特定参数取代该动态值。</p>
<p>3) 将脚本中所有出现的动态值都替换为参数。</p>
<p>4) 检查变化。</p>
<p>录制脚本</p>
<p>获得时标 &amp; 校验和</p>
<p>时标 = TSnew，校验和 = CSnew</p>
<p>网络 服务器</p>
<p>开始新一轮会话：TSnew &amp; CSnew</p>
<p>OK 会话开始</p>
<p>客户端</p>
<p>解析<a  href="http://www.qqread.com/tag/3159/index.html" target="_blank">服务器端</a>响应，并捕获 TSnew &amp; CSnew</p>
<p>现在，我要开始就每一步进行解释：</p>
<p>1) 找到一个需要捕获的动态值</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 我建议先录制并保存两段相同的虚拟脚本。再打开主菜单项中的&#8220;Tools / Compare with Scripts...&#8221;，用 WDiff 比较这两段录制的脚本：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_5.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_5.jpg" alt="在LoadRunner 脚本中使用关联（图五）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p>&nbsp;&nbsp;&nbsp; 黄色标出的地方即不同处。意味着每次脚本运行至该处，代码（参数值）就会发生变化。所以，多数情况下，这些值是需要关联的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 提示：有时通过比较可能找不到动态值。那您需要再次确认是否已录制了该段脚本：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Name=SessionID", "Value=A38E9002A41", ENDITEM, "Name=CurrentMonthID", "Value=4", ENDITEM,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显而易见，那个会话 ID 应该被关联。那 CurrentMonthID
呢？第二次录制的脚本也包含&#8220;Value=4&#8221;。也有可能您的脚本在四月份是工作正常的（4th month 即四月），而到
5月1日开始就会报错！所以亲爱的读者们要特别小心！ 提示：通篇察看您录制的脚本源码。时标、检验和、会话 ID 以及那些不同的 ID
都可能需要被关联。 提示：仔细检查回放（执行）日志，错误可能就在里面。往往脚本错误最普遍的原因就是缺少关联。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;提示：在可用的运行视图（菜单&#8220;Tools / General Options../ Display&#8221;）中执行脚本。当出现错误（&#8220;Page not found&#8221;，&#8220;Session timeout&#8221;等）就是在暗示可能存在关联。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 提示：在可用的运行视图（菜单&#8220;Tools / General Options../ Display&#8221;）中执行脚本。当出现错误（&#8220;Page not found&#8221;，&#8220;Session timeout&#8221;等）就是在暗示可能存在关联。</p>
<p>2) 找到<a  href="http://www.qqread.com/network/server/index.html" target="_blank">服务器</a>包含该动态值的响应</p>
<p>&nbsp;&nbsp; 在执行脚本前，请设置扩展日志为可用（&#8220;Vuser / Run-Time Settings...&#8221;）：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_6.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_6.jpg" alt="在LoadRunner 脚本中使用关联（图六）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p>&nbsp; 然后执行脚本。</p>
<p>&nbsp;&nbsp; 打开回放（执行）日志并找到服务器的响应（包含时标、检验和的动态值）：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_7.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_7.jpg" alt="在LoadRunner 脚本中使用关联（图七）" width="570" border="0"> <center>点击查看大图</center></a></p>
<div id="w_hzhbig">
<script type="text/javascript"><!--
google_ad_client = "pub-1572879403720716";
google_ad_width =" 300;
google_ad_height" = 250;
google_ad_format =" "300x250_as";
google_ad_type" = "text_image";
//inner 300hzh - qqread
google_ad_channel =" "5367608466";
google_color_border" = "f7fcff";
google_color_bg =" "f7fcff";
google_color_link" = "ff6600";
google_color_text =" "000000";
google_color_url" = "003366";
//-->
</script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js"></script>
<script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"></script>
<script>window.google_render_ad();</script>
<ins style="border: medium none ; margin: 0pt; padding: 0pt; display: inline-table; height: 250px; position: relative; visibility: visible; width: 300px;"><ins style="border: medium none ; margin: 0pt; padding: 0pt; display: block; height: 250px; position: relative; visibility: visible; width: 300px;"><iframe allowtransparency="true" hspace="0" id="google_ads_frame1" marginheight="0" marginwidth="0" name="google_ads_frame" src="http://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-1572879403720716&amp;dt=1235962798840&amp;lmt=1233592381&amp;format=300x250_as&amp;output=html&amp;correlator=1235962798840&amp;channel=5367608466&amp;url=http%3A%2F%2Fwww.qqread.com%2Fsoft-engineering%2Fe449193_2.html&amp;color_bg=F7FCFF&amp;color_text=000000&amp;color_link=FF6600&amp;color_url=003366&amp;color_border=F7FCFF&amp;ad_type=text_image&amp;ref=http%3A%2F%2Fwww.qqread.com%2Fsoft-engineering%2Fe449193.html&amp;frm=0&amp;ga_vid=877242290.1235962539&amp;ga_sid=1235962539&amp;ga_hid=278251773&amp;ga_fc=true&amp;flash=10.0.12&amp;u_h=800&amp;u_w=1280&amp;u_ah=766&amp;u_aw=1280&amp;u_cd=32&amp;u_tz=480&amp;u_his=2&amp;u_nplug=11&amp;u_nmime=35&amp;dtd=74&amp;w=300&amp;h=250&amp;xpc=GTyTck6eTy&amp;p=http%3A//www.qqread.com" style="left: 0pt; position: absolute; top: 0pt;" vspace="0" scrolling="no" width="300" frameborder="0" height="250"></iframe></ins></ins>
</div>
<p>&nbsp; 好！我们已经找到服务器发送动态值的地方了。而且我们也找到了返回该值的步骤——第 13 行 Action.c (13)。双击该行，连同时标以及检验和的值，打开第 13 行代码：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;web_submit_data("generateChecksum.jsp", </p>
<p>&nbsp; "Action=http://eprumossd0010:8400/RMS/jsp/generateChecksum.jsp", </p>
<p>&nbsp; "Method=POST", "RecContentType=text/html",</p>
<p>&nbsp;&nbsp;&nbsp; 这就表示服务器响应页面，generateChecksum.jsp 内包含应被关联的动态值。</p>
<p>3) 捕获动态值</p>
<p>&nbsp; 我将演示两种方法来捕获动态值：</p>
<p>&nbsp;&nbsp;&nbsp; A. 从树视图中自动捕获</p>
<p>&nbsp;&nbsp;&nbsp; B. 从脚本视图中手动捕获</p>
<p>这两种方法很相似，也使用相同的函数 — web_reg_save_param。 开始：</p>
<p>&nbsp;&nbsp;&nbsp; A.从树视图中自动捕获</p>
<p>打开树视图（菜单&#8220;View / Tree view&#8221;）：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_8.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_8.jpg" alt="在LoadRunner 脚本中使用关联（图八）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p>然后：</p>
<p>? 点击&#8220;View recording snapshot only&#8221;按钮 (2)；</p>
<p>? 从树视图中选择 generateChecksum.jsp 页面 (3)；</p>
<p>? 选择&#8220;Body&#8221;查看<a  href="http://www.qqread.com/network/server/index.html" target="_blank">服务器</a>响应的整体内容 (4)；</p>
<p>? 从中您将看到已录制的时标以及检验和的值 (5)。</p>
<p>现在让我们选择第一个动态值（检验和），右击并选择&#8220;Create parameter&#8221;，以创建参数：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_9.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_9.jpg" alt="在LoadRunner 脚本中使用关联（图九）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p><clk>&nbsp;您可以开始为动态值创建参数。 如果您需要替换所有脚本中出现的动态值，请按&#8220;Yes&#8221;按钮。如果不要替换所有的，请按&#8220;No&#8221;按钮。 提示：我不建议替换所有的动态值，因为很有可能导致错误。相反，通过&#8220;Search and Replace&#8221;对话框逐个替换的<nobr id="clickeyekey0" style="border-bottom: 1px dotted #6600ff; text-decoration: underline; color: #6600ff; background-color: transparent;" onclick="'kwC(event,0,"")'" oncontextmenu="return false" onmouseover="kwE(event,0, this)" onmouseout="kwL(event,this)" onmousemove="kwM(0)">效果</nobr>更好。 OK，我按了&#8220;No&#8221;按钮。</clk></p>
<p>返回脚本视图（&#8220;View / Script View&#8221;）查看变化。可以发现generateChecksum.jsp 页面前会出现新行：</p>
<p>&nbsp;&nbsp;&nbsp; //[WCSPARAM WCSParam_Text1 40
715E19300D670ED77773BBF066DAAAE2866484B8] Parameter {WCSParam_Text1}
created by Correlation Studio web_reg_save_param("WCSParam_Text1",
"LB=window.parent.setChecksum(\"", "RB=\"", "Ord=1", "RelFrameId=1",
"Search=Body", "IgnoreRedirections=Yes", LAST);</p>
<p><clk>&nbsp;web_reg_save_param 函数将从下一个服务器响应中查找并储存一个字符串。换句话说，它会捕获一个动态值。
在这个例子里，web_reg_save_param 函数将会把捕获的值保存在参数 WCSParam_Text1
中，并会发现左边界（window.parent.setChecksum("）和右边界（"）。从左右边界之内找到的字符串将保存到参数
WCSParam_Text1 中。Ord 属性注明了被捕获值的顺序位置。本例中（Ord=1），即我们捕获的值处于左边界和左边第一个值之间。
容易想到的是，&#8220;Search=Body&#8221;意思是在服务器响应的实体内搜索。我建议通过 Help 进一步<nobr id="clickeyekey1" style="border-bottom: 1px dotted #6600ff; text-decoration: underline; color: #6600ff; background-color: transparent;" onclick="'kwC(event,1,"")'" oncontextmenu="return false" onmouseover="kwE(event,1, this)" onmouseout="kwL(event,this)" onmousemove="kwM(1)">学习</nobr> web_reg_save_param 函数。 注意：捕获时标参数的方法是类似的。其生成的代码如下：</clk></p>
<p>&nbsp;&nbsp;&nbsp; // [WCSPARAM WCSParam_Text2 13 1192177661211] Parameter
{WCSParam_Text2} created by Correlation Studio
web_reg_save_param("WCSParam_Text2", "LB=, ", "RB=)", "Ord=1",
"RelFrameId=1", "Search=Body", "IgnoreRedirections=Yes", LAST);</p>
<p>&nbsp;&nbsp;&nbsp; ? 从脚本视图中手动捕获。</p>
<p>&nbsp;&nbsp;&nbsp; 事实上，这个方法与手动编辑 web_reg_save_param
函数相结合。它要求对这个函数及其参数非常熟悉。web_reg_save_param 函数有许多属性，在此我不再重复说明，请大家参考 Help。
提示：我建议重命名默认参数（WCSParam_Text1， 2， 3， etc），方便记忆。例如在此例中，我喜欢将参数 prmCheckSum
和 prmTimeStamp 重命名为 WCSParam_Text1 和 WCSParam_Text2。</p>
<p>4) 将脚本中所有出现的动态值都替换为参数</p>
<p>&nbsp;&nbsp;&nbsp; 将脚本中所有出现的动态值都替换为参数。 打开&#8220;Search and Replace&#8221;对话框（&#8220;Edit/Replace...&#8221;），并逐个将硬编码替换为参数。 其重要性何在？</p>
<p>&nbsp;&nbsp;&nbsp; 试想，您有以下源码：</p>
<p>&nbsp;&nbsp;&nbsp; web_submit_data("somepage", ... </p>
<p>&nbsp;&nbsp;&nbsp; "Name=OrderNumber", "Value=125", ENDITEM, </p>
<p>&nbsp;&nbsp;&nbsp; "Name=UserID", "Value=125",</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 如果您为 UserID 创建参数，并替换其所有的值（&#8220;125&#8221;），那么其就会生成代码：</p>
<p>&nbsp;&nbsp;&nbsp; web_submit_data("somepage", ... </p>
<p>&nbsp;&nbsp;&nbsp; "Name=OrderNumber", "Value={WCSParam_Text1}", ENDITEM, </p>
<p>&nbsp;&nbsp;&nbsp; "Name=UserID", "Value={WCSParam_Text1}",</p>
<p>&nbsp;&nbsp;&nbsp; 就会产生这样的错误：当 UserID 变化，OrderNumber 可能就会变为固定值 125。 现在我能确保您已经成功替换所有需要替换的硬编码。让我们开始执行最后一步：</p>
<p>&nbsp;&nbsp;&nbsp; 5) 检查变化</p>
<p>&nbsp;&nbsp;&nbsp; 经过以上操作，我们的代码将变为：&nbsp;&nbsp;</p>
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 98%;">
<div>
<p>Code highlighting produced by Actipro CodeHighlighter (freeware)</p>
<p>http://www.CodeHighlighter.com/</p>
<p>--&gt;web_submit_data("rms.jsp",
"Action=http://eprumossd0010:8400/RMS/jsp/rms.jsp", "Method=POST",
"RecContentType=text/html",
"Referer=http://eprumossd0010:8400/RMS/html/testFramework.html",
"Snapshot=t4.inf", "Mode=HTML", ITEMDATA, "Name=TIMESTAMP",
"Value={WCSParam_Text2}", ENDITEM, "Name=CHECKSUM",
"Value={WCSParam_Text1}", ENDITEM, // others parameters ... LAST);</p>
</div>
</div>
<p>&#8220;{WCSParam_Text1}&#8221;表示&#8220;获取 WCSParam_Text1 参数的值&#8221;。</p>
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 98%;">
<div>
<p>Code highlighting produced by Actipro CodeHighlighter (freeware)</p>
<p>http://www.CodeHighlighter.com/</p>
<p>--&gt;web_submit_data("rms.jsp",
"Action=http://eprumossd0010:8400/RMS/jsp/rms.jsp", "Method=POST",
"RecContentType=text/html",
"Referer=http://eprumossd0010:8400/RMS/html/testFramework.html",
"Snapshot=t4.inf", "Mode=HTML", ITEMDATA, "Name=TIMESTAMP",
"Value={WCSParam_Text2}", ENDITEM, "Name=CHECKSUM",
"Value={WCSParam_Text1}", ENDITEM, // others parameters ... LAST);</p>
<p>web_submit_data("somepage", ... "Name=OrderNumber", "Value=125", ENDITEM, "Name=UserID", "Value=125",</p>
<p>web_submit_data("somepage", ... "Name=OrderNumber", "Value={WCSParam_Text1}", ENDITEM, "Name=UserID", "Value={WCSParam_Text1}",</p>
</div>
</div>
<p>&nbsp;&nbsp;&nbsp; 所以，现在的规则是：</p>
<p>? 当<a  href="http://www.qqread.com/network/server/index.html" target="_blank">服务器</a>返回不同的检验和、时标值时</p>
<p>? web_submit_data 会捕获并将其置于变量 WCSParam_Text1 和 WCSParam_Text2 中</p>
<p>? 然后，我们使用 {WCSParam_Text1} 和 {WCSParam_Text2} 获得变量的当前值，并将其用到脚本中去。</p>
<p>运行修改后的脚本，并观察捕获的服务器响应的结果：</p>
<p>&nbsp;&nbsp; 图10</p>
<p>您可以看到动态值被保存至变量。很好！我们刚完成了脚本关联！</p>
<p>提示：使用以下语句获得并调试变量捕获的值：</p>
<p>&nbsp; lr_output_message("Value of WCSParam_Text1:%s", lr_eval_string("{WCSParam_Text1}"));</p>
<p>&nbsp; &nbsp;lr_output_message("Value of WCSParam_Text2:%s", lr_eval_string("{WCSParam_Text2}"));</p>
<p>再次执行，结果是：</p>
<p align="center"><a  href="http://www.qqread.com/ArtImage/20090202/ap58_10.jpg" target="_blank"><img  src="http://www.qqread.com/ArtImage/20090202/ap58_10.jpg" alt="在LoadRunner 脚本中使用关联（图十）" width="570" border="0"> <center>点击查看大图</center></a></p>
<p><clk>&nbsp;结束语： 我以尽可能简单易懂的<nobr id="clickeyekey0" style="border-bottom: 1px dotted #6600ff; text-decoration: underline; color: #6600ff; background-color: transparent;" onclick="'kwC(event,0,"")'" oncontextmenu="return false" onmouseover="kwE(event,0, this)" onmouseout="kwL(event,this)" onmousemove="kwM(0)">语言</nobr>解释了 LoadRunner 中的关联功能。亲爱的读者，非常欢迎您也能分享自己的意见和想法。 参考文献：</clk></p>
<p>? Using parameters in Loadrunner VuGen script</p>
<p>? LoadRunner Correlation - How to capture an array of dynamic data with web_reg_save_param function</p>
<p>? What are LoadRunner parameter and parameterization?</p>
<p>? Boundaries for web_reg_save_param LoadRunner function</p>
<p>? How to perform basic operations on LoadRunner parameters?</p><img src ="http://www.cnitblog.com/stomic/aggbug/54971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-02 11:01 <a href="http://www.cnitblog.com/stomic/archive/2009/03/02/54971.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LR高手进阶之关联</title><link>http://www.cnitblog.com/stomic/archive/2009/03/01/54962.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Sun, 01 Mar 2009 14:23:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/01/54962.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/54962.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/01/54962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/54962.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/54962.html</trackback:ping><description><![CDATA[<p><font size="3" color="#ff80c0"><strong>1.什么是关联？</strong></font></p>
<p><font size="2" color="#006666">关联是为了获取每次运行脚本的唯一数据值和通过嵌套查询生成的数据。关联提供了避免产生重复数据错误的数值以及优化代码（以避免嵌套查询）。<span style="font-size: 10pt; color: #006666;"><font face="宋体">关联是正常回放含有动态数据如<span lang="EN-US">Session IDs</span>，<span lang="EN-US">Database Primary Keys </span>和差不多所有的<span lang="EN-US">HTTP</span>安全机制脚本的根本。关联的目的就是吧脚本中某些hard-coded数据转变成从服务器传过来的动态的，每次执行都不一样的数据。</font></span></font></p>
<p><font size="2" color="#006666">2.参数（化）和关联的区别</font></p>
<p><font size="2" color="#006666">参数（化）相当于代码编写中的变量。是某个变量向服务器输入不同的值，用来模拟真
实的用户。运行脚本时，不同的数据集被发送给服务器。只能对某个具体的变量值进行参数化。参数化的对象在回放过程中即时没有被参数化也不会报错，只是像服
务器输入了相同的值。但是关联的对象在回放过程中如果没有做关联，回放过程中就会报错。关联是对系统的动态数据<font color="#006666">（每次运行脚本都会变化的值，是从服务器传过来的）</font>进行。简单的说，每一次执行时都会变动的值，就有可能需要做关联。</font></p>
<p><font size="2" color="#006666">3.动态关联和手工关联的区别</font></p>
<p><font size="2" color="#006666">动态关联是我们为关联设置规则，可以是具体的应用程序服务，这里的数据由所创建的
规则替代。在手工关联中，我们想要关联的数值被扫描并且编写关联函数完成关联。VuGen内建自动关联引擎（auto-correlation
engine）,可以自动找出需要关联的值，并可以利用关联函数自动建立关联。</font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 150%;"><font size="2" color="#006666">手动关联需要自行查找关联的对象，然后自行插入关联函数。</font></p>
<p><font size="2" color="#006666">4.如何发现哪里需要关联？</font></p>
<p><font size="2" color="#006666">两种方式：首先回放扫描不同的值然后看哪些值需要关联。其次，我们可以录制2个脚
本然后作比较。我们可以查看不同的文件决定需要关联的数据。在我实践的某个项目中，为每个用户提供一个唯一的ID，一个不确定的数字，是自动生成的，有序
且值唯一。我需要关联这个ID值以防止在运行脚本是出现错误。我用的是扫描的方式关联。</font></p>
<p><font size="2" color="#006666">5.在哪里设置自动关联选项？</font></p>
<p><font size="2" color="#006666">网页自动关联可以在<span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><font color="#006666">recording options --&gt;correlation tab<font size="2">栏设置。这里可以为全部脚本设置关联并选择是在线问题信息还是离线actions，我们也可为这些关联定义规则。数据库的自动关联可以用输出窗口、关联扫描、找关联查询项并选择要关联的查询值。如果知道需要关联的具体值，只需要为这些值创建关联并指定这些值是如何创建的。</font></font></span></font></p>
<font size="1" color="#006666"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">
<p><span style="font-size: 10pt; color: #006666; font-family: 'courier new';" lang="EN-US">6. </span><span style="font-size: 10pt; color: #006666;">在网页录制脚本中，什么函数能捕获动态数据？</span><span style="font-size: 10pt; color: #006666; font-family: 'courier new';" lang="EN-US"><o:p></o:p></span></p>
<p><span style="font-size: 10pt; color: #006666;" lang="EN-US">Web_reg_save_param</span><span style="font-size: 10pt; color: #006666;">函数可以将动态数据信息保存到一个参数中。</span></p>
<span style="font-size: 10pt; color: #006666;">
<p><span style="font-size: 10pt; color: #006666;" lang="EN-US">Web_reg_save_param</span><span style="font-size: 10pt; color: #006666;">函数语法：<span lang="EN-US"><o:p></o:p></span></span></p>
<p><span style="font-size: 10pt; color: #006666;" lang="EN-US">int web_reg_save_param (const char *mpszParamName, &lt;List of Attributes&gt;, LAST); <o:p></o:p></span></p>
<p><a name="wp61073"></a><span style="font-size: 10pt; color: #006666;">以下表格列出了可获取到的属性<span lang="EN-US">. </span>注意属性值字符串没有大小写区分（例如：<span lang="EN-US">Search=all</span>）<span lang="EN-US"><o:p></o:p></span></span></p>
<p>
</p>
<table class="MsoNormalTable" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61076"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">NotFound <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61078"></a><span style="font-size: 10pt; color: #006666;">边界找不到或空字符串生成时的处理方法。默认值为&#8220;<span lang="EN-US">Error</span>&#8221;，说明当边界值找不到时，<span lang="EN-US">VuGen</span>可以作为一个错误提出。当设置为&#8220;<span lang="EN-US">EMPTY</span>&#8221;<span lang="EN-US">,</span>没有错误信息提出脚本继续执行。注意：如果脚本设置了<span lang="EN-US">Continue on Error</span>项，则当边界值没有找到时，脚本也会继续执行，但会早<span lang="EN-US">Extend log</span>文件中输出一个错误信息<span lang="EN-US"><o:p></o:p></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61080"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">LB <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61082"></a><span style="font-size: 10pt; color: #006666;">参数或动态数据的左边界。该参数必须是非空字符串。区分大小写。如果想忽略大小写，则用<span lang="EN-US">LB/IC</span>。如果要指定二进制数据用<span lang="EN-US">LB/BIN <o:p></o:p></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61084"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">RB <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61086"></a><span style="font-size: 10pt; color: #006666;">参数或动态数据的右边界。该参数必须是非空字符串。区分大小写。如果不想区分大小写，则用<span lang="EN-US">RB/IC</span>。如果要指定二进制数据用<span lang="EN-US">RB/BIN <o:p></o:p></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61088"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">RelFrameID <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61090"></a><span style="font-size: 10pt; color: #006666;">相对于请求的<span lang="EN-US">URL</span>，<span lang="EN-US">HTML</span>页面的层次（<span lang="EN-US">hierarchy level</span>）。可以是<span lang="EN-US">All</span>或者是一个数字 <span lang="EN-US"><o:p></o:p></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61092"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">Search <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61094"></a><span style="font-size: 10pt; color: #006666;">查询的范围—去哪里查看分割数据。可选值有：<span lang="EN-US">Headers (search only the headers), Body (search only Body data, not headers), or ALL (search Body and headers)</span>。默认值是<span lang="EN-US">ALL</span>。 <span lang="EN-US"><o:p></o:p></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61096"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">ORD <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61098"></a><span style="font-size: 10pt; color: #006666;">可选参数。指定匹配项的顺序或出现数（<span lang="EN-US">the ordinal or occurrence number of the match</span>）。默认值为<span lang="EN-US">1</span>，如果指定是&#8220;<span lang="EN-US">ALL</span>&#8221;，则将参数值保存在一个数值里。 <span lang="EN-US"><o:p></o:p></span></span></p>
            </td>
        </tr>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61100"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">SaveOffset <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61102"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">The
            offset of a sub-string of the found value, to save to the parameter.
            The default is 0. The offset value must be non-negative. <o:p></o:p></span></p>
            </td>
        </tr>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61104"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">Savelen <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61106"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">The
            length of a sub-string of the found value, from the specified offset,
            to save to the parameter. The default is -1, indicating until the end
            of the string. <o:p></o:p></span></p>
            </td>
        </tr>
        <tr>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61108"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">Convert <o:p></o:p></span></p>
            </td>
            <td style="border: medium none #ece9d8; padding: 3.75pt; background-color: transparent;">
            <p><a name="wp61110"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">The conversion method to apply to the data: <o:p></o:p></span></p>
            <p><a name="wp61111"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">HTML_TO_URL: convert HTML-encoded data to a URL-encoded data format <o:p></o:p></span></p>
            <p><a name="wp61112"></a><span style="font-size: 10pt; color: #006666;" lang="EN-US">HTML_TO_TEXT: convert HTML-encoded data to plain text format <o:p></o:p></span></p>
            </td>
        </tr>
    </tbody>
</table>
<span lang="EN-US"><o:p></o:p></span></span>
</span></font>
<p><span style="font-size: 10pt; color: #006666; font-family: 'courier new';" lang="EN-US">7.HTML</span><font face="宋体"><span style="font-size: 10pt; color: #006666;">页面中的动态数据可能存在于：</span><span style="font-size: 10pt; color: #006666; font-family: 'courier new';" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;"><span style="font-size: 10pt; font-family: symbol;" lang="EN"><span><font face="宋体"><img  src="file:///D:/DOCUME%7E1/ADMINI%7E1/LOCALS%7E1/Temp/msohtml1/07/clip_image001.jpg" alt="*" width="12" height="11"></font><span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-size: 10pt; color: teal; font-family: 宋体;">每次获取相关网页都变化的</span><span style="font-size: 10pt; color: teal;" lang="EN"><font face="Times New Roman">URL<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;"><span style="font-size: 10pt; font-family: symbol;" lang="EN"><span><font face="Times New Roman"><img  src="file:///D:/DOCUME%7E1/ADMINI%7E1/LOCALS%7E1/Temp/msohtml1/07/clip_image001.jpg" alt="*" width="12" height="11"><span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span></span><span style="font-size: 10pt; color: teal; font-family: 宋体;">在</span><span style="font-size: 10pt; color: teal;" lang="EN"><font face="Times New Roman">form</font></span><span style="font-size: 10pt; color: teal; font-family: 宋体;">提交过程中录制的字段（有时是隐藏的）</span><span style="font-size: 10pt; color: teal;" lang="EN"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;"><span style="font-size: 10pt; font-family: symbol;" lang="EN"><span><img  src="file:///D:/DOCUME%7E1/ADMINI%7E1/LOCALS%7E1/Temp/msohtml1/07/clip_image001.jpg" alt="*" width="12" height="11"><span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-size: 10pt; color: teal;" lang="EN"><font face="Times New Roman">JavaScritpt cookies</font></span></p>
<span style="font-size: 10pt; color: teal;" lang="EN">
<p><span style="font-size: 10pt; color: #006666;"><font face="宋体">第<span lang="EN-US">1</span>种情况：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p><span style="font-size: 10pt; color: #006666;"><font face="宋体">录制时，假设点击 &#8220;<span lang="EN-US">buy me now</span>！&#8221;文字的超链接，<span lang="EN-US">VuGen</span>录制的<span lang="EN-US">URL</span>是：<span lang="EN-US"><a  href="http://host/cgi-bin/purchase.cgi?date=170397&amp;ID=1234"><span style="color: #006666; text-decoration: none;">http://host//cgi-bin/purchase.cgi?date=170397&amp;ID=1234</span></a></span>因为<span lang="EN-US">date "<em>170397</em>"</span>和<span lang="EN-US"> ID "<em>1234</em>"</span>是在录制过程中自动生成的，每一次新的浏览会话重新生成新的<span lang="EN-US">date</span>和<span lang="EN-US">ID</span>。当运行脚本时，&#8220;<span lang="EN-US">Buy me now!</span>&#8221;链接的<span lang="EN-US">URL</span>不再是录制时的<span lang="EN-US">URL</span>而是一个新的了。因此，<span lang="EN-US">Web</span>服务器不能重新获得<span lang="EN-US">URL</span>。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p><span style="font-size: 10pt; color: #006666;"><font face="宋体">第<span lang="EN-US">2</span>种情况</font></span></p>
<p><span style="font-size: 10pt; color: #006666;"></span><span style="font-size: 10pt; color: #006666;"><font face="宋体">考虑一种情形：提交一个用户填写了他的姓名和帐号<span lang="EN-US">ID</span>的<span lang="EN-US">form</span>。当这个<span lang="EN-US">form</span>提交时，一个唯一的序列号和该用户的数据同时也一起提交给了服务器。这个序列号是<span lang="EN-US">HTML</span>代码中一个隐藏字段的值，被<span lang="EN-US">VuGen</span>录制到了脚本中。因为这个序列号在每次浏览会话中都会变，所以<span lang="EN-US">Vuser</span>不能成功回放录制的脚本。</font></span></p>
<span style="font-size: 10pt; color: #006666;"><font face="宋体">
<p><span style="font-size: 10pt; color: #006666;" lang="EN-US">8.</span><span style="font-size: 10pt; color: #006666;">如果右界不一致，指定一个右边界是不够的，需要指定可选右边界。因为它不一致<span lang="EN-US">---</span>例如有时是<span lang="EN-US">&#8221;@&#8221;</span>有时是&#8220;<span lang="EN-US">&amp;</span>&#8221;。这种情况下，指定<span lang="EN-US">&amp;</span>为可选择的右边界。</span></p>
</font></span></span><img src ="http://www.cnitblog.com/stomic/aggbug/54962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-01 22:23 <a href="http://www.cnitblog.com/stomic/archive/2009/03/01/54962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>测试工具Loadrunner日志参数的设置与使用 --http://epan-chen.javaeye.com/blog/317594</title><link>http://www.cnitblog.com/stomic/archive/2009/03/01/54957.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Sun, 01 Mar 2009 07:42:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/03/01/54957.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/54957.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/03/01/54957.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/54957.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/54957.html</trackback:ping><description><![CDATA[<strong>一、Run-Time Setting日志参数的设置</strong> <br>
<br>
在loadrunner的vuser菜单下的Run-Time Setting的General的LOG选项中可以对在执行脚本时Loadrunner对日志的操作行为进行定义，下面我们在逐一介绍：<br>
<br>
1、&nbsp; Enable logging启用日志记录<br>
<br>
如果选中该选项Loadrunner在执行脚本时，进行日志的记录，否则不记录日志<br>
<br>
2、&nbsp; Send messages only when an error occurs 仅在出错时发送消息<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也称为 JIT （实时）消息传递，仅当错误发生时才写入日志，选择该选项后则可以设置高级选项，指明日志缓存的大小，loadrunner默认的日志到小为1k<br>
<br>
3、&nbsp; Always send messages<br>
<br>
始终发送消息<br>
<br>
4、&nbsp; Standard log<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 标准日志：创建在脚本执行期间发送的函数和消息的标准日志，供调试时使用。<br>
<br>
对于大型负载测试场景、优化会话或配置文件禁用此选项。<br>
<br>
如果日志记录级别设置为&#8220;标准&#8221;，当把脚本添加到场景、会话步骤或配置文件<br>
<br>
中时，日志记录模式将被自动设置为&#8220;Send messages only when an error occurs&#8221;。但是，如果日志记录模式被禁用或者设置为&#8220;扩展&#8221;，则将脚本添加到场景、会话步骤或配置文件中将不会影响其日志记录设置。<br>
<br>
5、&nbsp; Extended log-----Parameter substitution<br>
<br>
参数替换：选择此选项可以记录指定给脚本的所有参数及其相应的值<br>
<br>
当脚本进行参数化、插入事务、关联等优化后，在执行脚本过程中，参数化的值、事务所耗时间、关联函数取出的变量值均会在日志中输出，这个选项对调试脚本查看参数化取值、关联取值是否正确有着重要的作用<br>
<br>
6、&nbsp; Extended log-----Data returned by server<br>
<br>
&nbsp;&nbsp; 选择此选项可以记录服务器返回的所有数据。<br>
<br>
&nbsp;&nbsp; Loadrunner会将所有对服务器发出请求后的response情况记录在日志中，从这个日志中可以查看到服务器对请求的回应是否正确，在使用关联取值时往往需要到该日志中查看需要关联的值，从而确认所取数据左右边界。<br>
<br>
7、&nbsp; Extended log-----Advanced trace&nbsp; 高级跟踪<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 选择此选项可以记录 Vuser 在会话期间发送的所有函数和消息。<br>
<br>
调试 Vuser 脚本时，该选项非常有用。<br>
<br>
<strong>二、日志函数的使用</strong> <br>
<br>
Loadrunner提供了一下几个message函数：<br>
1、lr_message<br>
int lr_message (const char * format, exp1, exp2,...expn.);<br>
中文解释：lr_message函数将信息发送到日志文件和输入窗口。在VuGen中运行时，输入文件为output.txt。<br>
<br>
例如：<br>
<br>
char* abort="aborting"; <br>
<br>
&nbsp; lr_message ("login failed: %s", abort);<br>
<br>
&nbsp;&nbsp;&nbsp; 在日志中将会看到:login failed: aborting<br>
<br>
2、lr_log_message<br>
int lr_log_message (const char * format, exp1, exp2,...expn.);<br>
中文解释：lr_log_message函数将消息发送到Vuser或代理日志文件（取决于应用程序），而不是发送到输出窗口。通过向日志文件发送错误消息或其他信息性消息，可以将该函数用于调试。<br>
<br>
3、lr_error_message<br>
int lr_error_message (const char *format, exp1, exp2,...expn. );<br>
中文解释：lr_error_message函数将错误消息发送到输出窗口和Vuser日志文件。<br>
<br>
如果Run-time settings &gt; General &gt; Miscellaneous &gt;Continue on
error未被选中，当脚本执行到此处时将终止执行，这个函数所输出的错误级别较高的信息，所以一般情况下如果使用该函数时选中Continue on
error<br>
<br>
4、lr_output_message<br>
int lr_output_message (const char *format, exp1, exp2,...expn.);<br>
中文解释：lr_output_message函数将带有脚本部分的行号的消息发送到输出窗口和日志文件。<br>
<br>
<br>
<br>
三、在脚本中定义日志的输出模式<br>
<br>
int lr_debug_message (unsigned int message_level, const char *format, ... );<br>
<br>
中文解释：lr_debug_message函数在指定的消息级别处于活动状态时发送一条调试信息。如果指定的消息级别未出于活动状态，则不发送消息。您
可以从用户界面或者使用lr_set_debug_message，将处于活动状态的消息级别设置为MSG_CLASS_BRIEF_LOG
或MSG_CLASSS_EXTENDED_LOG。要确定当前级别，请使用lr_get_debug_message。<br>
<br>
unsigned int lr_get_debug_message ( );<br>
中文解释：lr_get_debug_message函数返回当前的日志运行时设置。该设置确定发送到输出端的信息。日志设置是使用运行时设置对话框或通过使用lr_set_debug_message函数指定的。<br>
<br>
int lr_set_debug_message (unsigned int message_level, unsigned int on_off);<br>
中文解释：lr_set_debug_message函数设置脚本执行的调试消息级别message_lvl。通过设置消息级别，可以确定发送哪些信息。
启 动设置的方法是将LR_SWITCH_ON作为on_off传递，禁用设置的方法是传递LR_SWITCH_OFF。<br>
<br>
参数message_level说明：<br>
<br>
日志级别<br>
&nbsp; C语言标志<br>
&nbsp; 值<br>
&nbsp; Runtime-setting - Log操作<br>
<br>
Disabled<br>
&nbsp; LR_MSG_CLASS_DISABLE_LOG<br>
&nbsp; 0<br>
&nbsp; 不勾选Enable logging<br>
<br>
Brief<br>
&nbsp; LR_MSG_CLASS_BRIEF_LOG<br>
&nbsp; 1<br>
&nbsp; 勾选Standard log<br>
<br>
Extended Log<br>
&nbsp; LR_MSG_CLASS_EXTENDED_LOG<br>
&nbsp; 16<br>
&nbsp; 勾选Extended log<br>
<br>
Result Data<br>
&nbsp; LR_MSG_CLASS_RESULT_DATA<br>
&nbsp; 2<br>
&nbsp; 勾选Data returned by server<br>
<br>
Parameter Substitution<br>
&nbsp; LR_MSG_CLASS_PARAMETERS<br>
&nbsp; 4<br>
&nbsp; 勾选Parameter substitution<br>
<br>
Full Run-Time Trace<br>
&nbsp; LR_MSG_CLASS_FULL_TRACE<br>
&nbsp; 8<br>
&nbsp; 勾选 Advanced trace<br>
<br>
Only on error<br>
&nbsp; LR_MSG_CLASS_JIT_LOG_ON_ERROR<br>
&nbsp; 512<br>
&nbsp; 勾选send messages only when an error occurs<br>
<br>
<br>
参数on_off说明：<br>
【LR_SWITCH_ON】启用设置<br>
【LR_SWITCH_OFF】禁用设置<br>
<br>
<br>
看下面的小例子：<br>
Action()<br>
{<br>
int log_leavl;<br>
log_leavl = lr_get_debug_message();<br>
lr_error_message ("当前是:%d",log_leavl);<br>
return 0;<br>
}<br>
当我设置只有错误信息(error)打印【勾选send messages only when an error
occurs】，例子运行结果是：当前是:513；为什么不是512呢，我发现我实际选择的是【Enable logging + send
messages only when an error
occurs】，按上面的参数说明，就是【1+512】，也就是513了；因此：lr_get_debug_message返回的int数其实是所有勾选
操作的代表值相加！<br>
<br>
再看下面设置的例子：<br>
<br>
Action()<br>
{<br>
//设置runtime-setting的日志选项【不勾选Enable logging】<br>
char *a;<br>
a = "ABC";<br>
lr_set_debug_message (LR_MSG_CLASS_EXTENDED_LOG |LR_MSG_CLASS_PARAMETERS,LR_SWITCH_ON);<br>
//打开Runtime-setting Log 的Parameter substitution设置<br>
lr_debug_message(LR_MSG_CLASS_PARAMETERS,"打开参数保存的系统日志");<br>
lr_save_string("aa",a);<br>
lr_debug_message(LR_MSG_CLASS_PARAMETERS,"关闭参数保存的系统日志");<br>
lr_set_debug_message (LR_MSG_CLASS_EXTENDED_LOG |LR_MSG_CLASS_PARAMETERS,LR_SWITCH_OFF);<br>
//关闭Runtime-setting Log 的Parameter substitution设置<br>
<br>
return 0;<br>
}<br>
<br>
因为设置了runtime-setting不打印任何日志，所以正常运行脚本应该没有任何日志输出；<br>
但是使用lr_set_debug_message函数打开了日志的设置(输出保存参数操作的日志)<br>
因此脚本运行到lr_save_string("aa",a)时，就输出了日志如下：<br>
<br>
打开参数保存的系统日志<br>
Action.c(7): Notify: Saving Parameter "ABC = aa"<br>
关闭参数保存的系统日志<img src ="http://www.cnitblog.com/stomic/aggbug/54957.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-03-01 15:42 <a href="http://www.cnitblog.com/stomic/archive/2009/03/01/54957.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>语句关联-《LoadRunner性能测试应用》</title><link>http://www.cnitblog.com/stomic/archive/2009/02/26/54898.html</link><dc:creator>大话人生</dc:creator><author>大话人生</author><pubDate>Thu, 26 Feb 2009 09:00:00 GMT</pubDate><guid>http://www.cnitblog.com/stomic/archive/2009/02/26/54898.html</guid><wfw:comment>http://www.cnitblog.com/stomic/comments/54898.html</wfw:comment><comments>http://www.cnitblog.com/stomic/archive/2009/02/26/54898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/stomic/comments/commentRss/54898.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/stomic/services/trackbacks/54898.html</trackback:ping><description><![CDATA[<h3>3.3&nbsp;
语句关联</h3>
<p class="WEB" style="text-indent: 21pt;">当录制脚本时，VuGen会拦截客户端（浏览器）与服务器端（网站服务器）之间的会话，并且记录下来，产生脚本。在VuGen的Recording
Log中，可以找到浏览器与服务器之间所有的对话，包含通信内容、日期、时间、浏览器的请求、服务器的响应内容等等。脚本和Recording Log最大的差别在于，脚本只记录了客户端要对服务器端所说的话，而Recording Log则是完整记录二者的对话。</p>
<p class="WEB" style="text-indent: 21pt;">当执行脚本时，可以把VuGen想象成是一个演员，它伪装成浏览器，然后根据脚本，把当初浏览器确实说过的话，再对网站服务器重新说一遍，VuGen企图骗过服务器，让服务器以为它就是当初的浏览器，然后把网站内容传送给VuGen。</p>
<p class="WEB" style="text-indent: 21pt;">所以VuGen记录在脚本中的要跟服务器所说的话，完全与当初录制脚本时所说的一样，是写死的（hard-coded）。这样的做法在遇到有些比较聪明的服务器时，还是会失效。这时就需要通过关联来让VuGen再次成功地骗过服务器。</p>
<h3>3.3.1&nbsp; 关联的意义</h3>
<p class="WEB" style="text-indent: 21pt;">所谓的关联就是把脚本中某些写死的代码（hard-coded）数据，转变成撷取自服务器所送的、动态的、每次都不一样的数据。</p>
<p class="WEB" style="text-indent: 21pt;">一般情况下，比较聪明的服务器在每个浏览器第一次跟它要数据时，
都会在数据中夹带一个唯一的辨识码，接下来就会利用这个辨识码来辨识跟它要数据的是不是同一个浏览器，一般称这个辨识码为Session
ID。对于每个新的请求，服务器都会产生新的Session ID给浏览器。这也就是执行脚本会失败的原因，因为VuGen还是用旧的Session
ID向服务器要数据，服务器发现这个Session ID是失效的或者它根本不认识这个Session
ID，当然就不会传送正确的网页数据给VuGen了。</p>
<p class="WEB" style="text-indent: 21pt;">下面的例子说明了这样的情形：</p>
<p class="WEB" style="text-indent: 21pt;">当录制脚本时，浏览器发出对网页A的请求，服务器将网页A的内容传送给浏览器，并且夹带了一个ID=123的数据，当浏览器再发出对网页B的请求时，这时就要用到ID=456的数据，服务器才会认为这是合法的请求，并且把网页B的内容送回给浏览器。</p>
<p class="WEB" style="text-indent: 21pt;">在执行脚本时会发生什么状况呢？浏览器再发出对网页B的请求时，用的还是当初录制的ID=123的数据，而不是用服务器新给的ID=456，因此整个脚本的执行就会失败。</p>
<p class="WEB" style="text-indent: 21pt;">要对付这种服务器，必须想办法找出这个Session ID到底是什么、位于何处，然后把它撷取下来，放到某个参数中，并且取代脚本中有用到Session ID的部分，这样就可以成功骗过服务器，正确地完成整个交易了。
</p>
<p class="41" style="text-indent: 21pt;">1．什么地方需要关联</p>
<p class="WEB" style="text-indent: 21pt;">凡是脚本每次执行时都必须获得唯一标识的地方都需要关联。假如脚
本需要关联，如果不做关联是不会执行通过的，也就是说会有错误消息发生。不过很遗憾，并没有任何特定的错误消息是和关联有关系的。会出现什么错误消息，与
系统实际的错误处理机制有关。错误消息有可能会提醒用户要重新登录，但是也有可能直接就显示HTTP 404的错误消息。 </p>
<p class="41" style="text-indent: 21pt;">2．如何做关联</p>
<p class="WEB" style="text-indent: 21pt;">关联会用到下列的函数：
</p>
<p class="4">&#376;&nbsp;&nbsp;
&nbsp;web_reg_save_param；</p>
<p class="4">&#376;&nbsp;&nbsp;
web_create_html_param；</p>
<p class="4">&#376;&nbsp;&nbsp;
web_create_html_param_ex；</p>
<p class="WEB" style="text-indent: 21pt;">其中，web_reg_save_param的语法为：</p>
<p class="ae" style="text-indent: 20.7pt;">web_reg_save_param (
"Parameter Name" , &lt; list of Attributes &gt;, LAST ); </p>
<p class="WEB" style="text-indent: 21pt;">web_create_html_param和web_create_html_param_ex这两个函数主要是保留以兼容以前旧版本。建议使用web_reg_save_param函数。</p>
<p class="WEB" style="text-indent: 21pt;">那么，如何找出要关联数据呢？简单地说，每一次执行时都会变动的值，就有可能需要做关联。VuGen提供两种方式帮助用户找出需要做关联的值：自动关联和手动关联。</p>
<h3>3.3.2&nbsp; 自动关联方法</h3>
<p class="WEB" style="text-indent: 21pt;">VuGen内建自动关联引擎（Auto-correlation Engine），提供Rules
Correlation和Correlation Studio两种机制，可以自动找出需要关联的值，并且自动使用关联函数建立关联。</p>
<p class="WEB" style="text-indent: 21pt;">1．&#8220;Rules
Correlation&#8221;：在录制过程中VuGen会根据使用者事先制订的规则，实时自动找出要关联的值。规则的来源有内建（Built-in
Correlation）和使用者自定（User-defined Rules Correlation）关联规则两种。</p>
<p class="4">&#376;&nbsp;&nbsp;
内建（Built-in
Correlation）：VuGen已经针对常用的一些应用系统，如AribaBuyer、BlueMartini、BroadVision、
InterStage、mySAP、NetDynamics、Oracle、PeopleSoft、Siebel、SilverJRunner等，内建了
一些关联规则。这些应用系统可能会有一种以上的关联规则。</p>
<p class="WEB" style="text-indent: 21pt;">可以在&#8220;Recording Options&#8221;&gt;&#8220;Internet
Protocol&#8221;&gt;&#8220;Correlation&#8221;中启用关联规则，启用关联后，当录制这些应用系统的脚本时，VuGen会在脚本中自动建立关联。也可以在&#8220;Recording
Options&#8221;&gt;&#8220;Internet Protocol&#8221;&gt;&#8220;Correlation&#8221;检视每个关联规则的定义。</p>
<p class="4">&#376;&nbsp;&nbsp;
除了内建的关联规则之外，使用者也可以自定关联规则。可以在&#8220;Recording Options&#8221;&gt;&#8220;Internet
Protocol&#8221;&gt;&#8220;Correlation&#8221;建立新的关联规则。</p>
<p class="WEB" style="text-indent: 21pt;">请依照以下步骤使用&#8220;Rule Correlation&#8221;：</p>
<p class="WEB" style="text-indent: 21pt;">单击VuGen的&#8220;Tools&#8221;&gt;&#8220;Recording
Options&#8221;，开启&#8220;Recording Options&#8221;对话窗口，选取&#8220;Internet
Protocol&#8221;&gt;&#8220;Correlation&#8221;，勾选&#8220;Enable correlation during
recording&#8221;，以启用自动关联。</p>
<p class="WEB" style="text-indent: 21pt;">假如录制的应用系统属于内建关联规则的系统，如
AribaBuyer、BlueMartini、BroadVision、InterStage、mySAP、NetDynamics、Oracle、
PeopleSoft、Siebel、SilverJRunner等，请勾选相对应的应用系统。或者也可针对录制的应用系统加入新的关联规则，此即为使用
者自定的关联规则。</p>
<p class="WEB" style="text-indent: 21pt;">自动关联时VuGen会侦测到符合关联规则的数据，以下为处理方式：</p>
<p class="WEB" style="text-indent: 21pt;">首先会跳出一个&#8220;Correlation
warning&#8221;消息对话窗口，选择&#8220;Issue a pop-up message and let me decide
online&#8221;：询问用户是否要建立关联，每遇到一次询问一次，以了解每个关联数据的内容和位置。如果每次询问很麻烦，可以选择&#8220;Perform
correlation in script&#8221;（直接自动建立关联）。</p>
<p class="WEB" style="text-indent: 21pt;">2．&#8220;Correlation
Studio&#8221;：有别于&#8220;Rules Correlation&#8221;，&#8220;Correlation
Studio&#8221;是在执行脚本后才会建立关联，也就是说当录制完脚本后，脚本至少须被执行过一次时&#8220;Correlation
Studio&#8221;才会起作用。&#8220;Correlation
Studio&#8221;会尝试找出录制时与执行时，服务器响应内容的差异部分，藉以找出需要关联的数据，并建立关联。</p>
<p class="WEB" style="text-indent: 21pt;">当录制的应用系统不属于VuGen预设支持的应用系统时，&#8220;Rule Correlation&#8221;可能无法发挥作用，这时可以利用&#8220;Correlation Studio&#8221;来进行关联。</p>
<p class="WEB" style="text-indent: 21pt;">使用&#8220;Correlation Studio&#8221;的步骤如下：</p>
<p class="WEB" style="text-indent: 21pt;">（1）录制脚本并执行。</p>
<p class="WEB" style="text-indent: 21pt;">（2）执行完毕后，VuGen会跳出&#8220;Scan Action for Correlation&#8221;窗口，询问用户是否要扫描脚本并建立关联，单击&#8220;Yes&#8221;按钮，扫描脚本。</p>
<p class="WEB" style="text-indent: 21pt;">（3）扫描完后，可以在脚本下方的&#8220;Correlation Results&#8221;中看到扫描的结果。</p>
<p class="WEB" style="text-indent: 21pt;">（4）检查一下扫描的结果，选择要做关联的数据，然后单击&#8220;Correlate&#8221;按钮，逐次关联，或是单击&#8220;Correlate All&#8221;让VuGen一次就对所有的数据建立关联。</p>
<p class="WEB" style="margin: 10pt 10.5pt 10pt 21pt; text-indent: 42pt; page-break-before: always;"><img  src="http://book.csdn.net/BookFiles/839/img/image156.jpg" width="78" height="31">由于Correlation Studio会找出所有有变动的数据，但是并不是所有的数据都需要做关联，所以不建议用户直接用&#8220;Correlate All&#8221;。</p>
<p class="WEB" style="margin-left: 21pt; text-indent: 21pt;">重复步骤（1）~（4），直到所有需要做关联的数据都找出来为止。</p>
<p class="WEB" style="margin: 10pt 10.5pt 10pt 21pt; text-indent: 42pt;"><img  src="http://book.csdn.net/BookFiles/839/img/image156.jpg" width="78" height="31">有时关联的地方有多处，前面的关联如果没有执行通过，执行将停止验证脚本的正确性，后面需要做关联的部分无法被扫描出来。</p>
<h3>3.3.3&nbsp; 手动关联方法</h3>
<p class="WEB" style="text-indent: 21pt;">在对脚本进行关联的时候，有的脚本利用上面介绍的方法自动关联就可以了，但是也有可能某些需要做关联的动态数据，连&#8220;Correlation Studio&#8221;都无法侦测出来，这时就需要进行手动关联。</p>
<p class="WEB" style="text-indent: 21pt;">虽然手动关联比自动关联方法麻烦一些，操作复杂，对于没有代码编程经验的测试初学者来说，甚至有时连需要关联的位置都无法找到，但是经过多次实践后，会发现很多关联的方法与技巧。毕竟手动关联出来的脚本拥有更大的灵活性，可以随意改动来满足用户不同的需求。</p>
<p class="WEB" style="text-indent: 21pt;">手动关联的执行过程大致如下：</p>
<p class="4">&#376;&nbsp;&nbsp;
使用相同的业务流程与数据，录制两份脚本。</p>
<p class="4">&#376;&nbsp;&nbsp;
使用WinDiff工具协助找出需要关联的数据。</p>
<p class="4">&#376;&nbsp;&nbsp;
使用web_reg_save_param函数手动建立关联。</p>
<p class="4">&#376;&nbsp;&nbsp;
将脚本中有用到关联的数据，以参数取代。</p>
<p class="WEB" style="text-indent: 21pt;">具体的执行过程如下：</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">1．使用相同的业务流程与数据，录制两份脚本。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">先录制一份脚本并存档，再依照相同的操作步骤与数据录制第二份脚本并保存。</p>
<p class="WEB" style="margin: 10pt 10.5pt 10pt 21pt; text-indent: 42pt;"><img  src="http://book.csdn.net/BookFiles/839/img/image053.jpg" width="78" height="31">所有的步骤和输入的数据一定都要一样，这样才能找出由服务器端产生的动态数据。在录制第二份脚本时有时候无法使用相同的输入数据，但也要记住第一份脚本所使用的输入数据，到时对两个脚本进行比较时才能判断出这是所要输入的数据，还是变动的数据。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">2．使用WinDiff工具协助找出需要关联的数据。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">（1）在第二份脚本中，单击VuGen的&#8220;Tools&#8221;&gt;&#8220;Compare
with Vuser&#8230;&#8221;，并选择第一份脚本。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">（2）接着
WinDiff会开启，同时显示两份脚本，并显示有差异的地方。WinDiff会以一整行黄色标示有差异的脚本，并且以红色的字体显示真正差异的文字（假
如没看到红色字体，请单击&#8220;Options&#8221;&gt;&#8220;View&#8221;&gt;&#8220;Show Inline Differences&#8221;）。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">（3）逐一检视两份脚本中差异的部分，每一处差异都可能是需要做关联的地方。选取差异的脚本，然后复制。在复制时，有时并不需要取整行脚本，可能只会选取脚本中的一部分。</p>
<p class="WEB" style="margin: 10pt 10.5pt 10pt 21pt; text-indent: 42pt;"><img  src="http://book.csdn.net/BookFiles/839/img/image053.jpg" width="78" height="31">请忽略lr_thik_time的差异部分，因为lr_thik_time是用来模拟每个步骤之间使用者思考延迟的时间的。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">（4）接着要在
Recording Log（单一协议）或是Generation Log（多重协议）中找这个值。将鼠标光标放到Recording
Log的第一行开头，按下&#8220;Ctrl+F&#8221;组合键，开启&#8220;Find&#8221;窗口，贴上刚刚复制的脚本，找出其在Recording Log第一次出现的位置。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">如果在Recording Log中找不到要找的数据，这时请先确认是否找对了脚本，毕竟现在开启了两个几乎一样的脚本，很容易弄错。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">如果在
Recording Log中找到了要找的数据，这时要确认数据是否为从服务器端传送过来的。首先可以检查数据的标头，从标头的Receiving
response可以知道数据是否是从服务器端传送到客户端的。假如此数据第一次出现是在Sending
request中，则表示此数据是由客户端产生，不需要做关联，但是有可能需要做参数化（Parameterized）。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">现在已经找到录制两次不一致而且是由服务器所产生的动态数据，此数据极有可能需要做关联。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">3．使用web_reg_save_param函数手动建立关联。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">在找到由服务器所产生的动态数据之后，接下来要做的就是找出适当的位置，使用web_reg_save_param函数，将这个动态数据撷取到某个参数中。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">（1）web_reg_save_param函数</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">对于关联来说，web_reg_save_param是最重要的一个函数，其功能是在下载的网页内容中，通过设定的边界字符串，找出特定的数据并将其存储在一个参数中，以供后续脚本使用。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">web_reg_save_param是一个服务端函数（Service function，主要用来完成一些特殊的工作，如关联、设定proxy、提供认证信息等），当其作用时，不会对网页的内容做任何的修改。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">web_reg_save_param
同时也是一个注册类型的函数（Registration Type
Function，只要函数名称中包含_reg_的字眼，表示其为注册类型的函数）。注册类型的函数意味着其真正作用的时机是在下一个动作函数
（Action
Function）完成时。举例来说，当某个web_url执行时所接收到的网页内容中包含了要做关联的动态数据，则必须将
web_reg_save_param放在此web_url之前，web_reg_save_param会在web_url执行完毕后，也就是网页内容都
下载完后，再执行web_reg_save_param，寻找要做关联的动态数据并建立参数。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">要记住一点，当使用注册类型的函数时，要注意其放置的位置必须在要作用的动作函数之前。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">（2）web_reg_save_param的语法</p>
<p class="ae" style="text-indent: 20.7pt;">int
web_reg_save_param(const char *ParamName, &lt;list of Attributes&gt;, LAST); </p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">参数说明：</p>
<p class="4">&#376;&nbsp;&nbsp;
ParamName：存放动态数据的参数名称。</p>
<p class="4">&#376;&nbsp;&nbsp;
list of Attributes：其他属性，包含 &#8220;Notfound&#8221;、&#8220;LB&#8221;、&#8220;RB&#8221;、&#8220;RelFrameID&#8221;、&#8220;Search&#8221;、&#8220;ORD&#8221;、&#8220;SaveOffset&#8221;、&#8220;Convert&#8221;以及&#8220;SaveLen&#8221;。下面将详细说明每个属性值的意义。</p>
<p class="WEB" style="margin: 0cm 0cm 0.0001pt; text-indent: 30.45pt; line-height: 17pt;">&#216;&nbsp; Notfound：指定当找不到要找的动态数据时该怎么处理。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">当指定Notfound=error时，表示着找不到动态数据时，就发出一个错误消息。此为该属性的默认值。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 16pt;">当指定Notfound=warning时，表示当找不到动态数据时，不发出错误消息，只发出警告，脚本也会继续执行下去不会中断。在对脚本出错时，可以如此设置。</p>
<p class="WEB" style="margin: 0cm 0cm 0.0001pt; text-indent: 30.45pt; line-height: 17pt;">&#216;&nbsp; LB：动态数据的左边界字符串。此属性是必须要有的，而且区分大小写。</p>
<p class="WEB" style="margin: 0cm 0cm 0.0001pt; text-indent: 30.45pt; line-height: 17pt;">&#216;&nbsp; RB：动态数据的右边界字符串。此属性是必须要有的，而且区分大小写。</p>
<p class="WEB" style="margin: 0cm 0cm 0.0001pt 43.6pt; text-indent: -13.15pt; line-height: 17pt;">&#216;&nbsp; RelFrameID：相对于URL而言，欲搜寻的网页的Frame。此属性可以是All或是数字，而且可有可无。</p>
<p class="WEB" style="margin: 0cm 0cm 0.0001pt 43.6pt; text-indent: -13.15pt; line-height: 17pt;">&#216;&nbsp;
Search：搜寻的范围，其值可以是Headers（只搜寻headers）、Body（只搜寻body部分，不搜寻header）、
Noresource（只搜寻body部分，不搜寻header与resource）或是All（搜寻全部范围，此为默认值），此属性可有可无。</p>
<p class="WEB" style="margin: 0cm 0cm 0.0001pt 43.6pt; text-indent: -13.15pt; line-height: 17pt;">&#216;&nbsp; ORD：指明从第几次出现的左边界开始才是要撷取的数据，默认值是1。假如该属性值为All，则所有找到符合的数据会存储在数组中。此属性可有可无。</p>
<p class="WEB" style="margin: 0cm 0cm 0.0001pt 43.6pt; text-indent: -13.15pt; line-height: 17pt;">&#216;&nbsp; SaveOffset：当找到符合的动态数据时，从第几个字符开始才开始存储到参数中。此属性值不可为负数，其默认值为0。</p>
<p class="WEB" style="margin: 0cm 0cm 0.0001pt 43.6pt; text-indent: -13.15pt; line-height: 17pt;">&#216; &nbsp;Convert：转换数据格式。当指定该属性值为HTML_TO_URL时，意味着将HTML-encoded数据转成URL-encoded数据格式。如果是HTML_TO_TEXT，表示将HTML-encoded数据转成纯文字数据格式。</p>
<p class="MsoNormal" style="text-indent: 21pt; line-height: 150%;">&#216;&nbsp; SaveLen：当找到匹配项后，偏移量之后的几个字元存储到参数中。此参数可有可无，默认值是-1，表示一直到结尾的整个字符串都存入参数中。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">（3）确定使用web_reg_save_param函数的位置</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">之前的步骤已经在
Execution Log中找到可能需要关联的动态数据。在Execution
Log中选取动态数据前的文字，然后复制，利用这段文字，找出要关联的动态数据。不过在这之前，需要先找出使用web_reg_save_param函数
的正确位置，所以要再重新执行一遍脚本，而且这次会开启所有的Log。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">在VuGen中单击
&#8220;Vuser&#8221;&gt;&#8220;Run-Time Settings&#8221;。单击&#8220;General&#8221;&gt;&#8220;Log&#8221;，勾选&#8220;Enable
logging&#8221;、&#8220;Always sends messages&#8221;、&#8220;Extended log&#8221;以及&#8220;Extended
log&#8221;下的所有选项。然后，单击&#8220;OK&#8221;按钮就可以执行脚本了。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">执行完脚本之后，在Execution Log中搜寻刚刚复制的字符串。找到字符串后，在字符串前面会有A.tion1.c(7)，这个7就是到时候要插入web_reg_save_param函数的位置，也就是说要插入到脚本的第7行。</p>
<p class="WEB" style="text-indent: 21pt; line-height: 17pt;">在脚本的第7行前插入一行空白行，然后输入：</p>
<p class="ae" style="text-indent: 20.7pt;">web_reg_save_param("UserSession",
</p>
<p class="WEB" style="text-indent: 21pt;">这个&#8220;UserSession&#8221;就是到时要使用的参数名称，建议取一个有意义的名字。</p>
<p class="WEB" style="margin: 10pt 10.5pt 10pt 21pt; text-indent: 42pt;"><img  src="http://book.csdn.net/BookFiles/839/img/image053.jpg" width="78" height="31">到目前为止，整个web_reg_save_param函数还没完成。</p>
<p class="WEB" style="text-indent: 21pt;">（4）确定web_reg_save_param中的边界。</p>
<p class="WEB" style="text-indent: 21pt;">web_reg_save_param函数主要是通过动态数据前后的固定字符串，来辨识要撷取的动态数据的，所以还需要找出动态数据的边界字符串。</p>
<p class="WEB" style="text-indent: 21pt;">1）确定左边界字符串</p>
<p class="WEB" style="text-indent: 21pt;">再回到Execution Log中，选取动态数据前的字符串并且复制它。这时会有个问题，到底要选取多少字符串才足以唯一识别要找的动态数据呢？建议是越多越好，但是尽量不要包含特殊字符。</p>
<p class="WEB" style="text-indent: 21pt;">选取&#8220;input type=hidden name=userSession value=&#8221;字符串，之后再确认一次这段字符串真的是可以唯一识别的，所以在Execution
Log中通过&#8220;Ctrl+F&#8221;搜寻，查看这段字符串是不是要找的动态数据。假如找不到，web_reg_save_param函数还有个ORD参数可以使用，ORD参数可以设定出现在第几次的字符串才是要找的字符串。</p>
<p class="WEB" style="text-indent: 21pt;">将这个边界字符串加到未完成的web_reg_save_param函数中： </p>
<p class="ae" style="text-indent: 20.7pt;">web_reg_save_param(UserSession",
"LB= input type=hidden name= userSession value=", </p>
<p class="WEB" style="text-indent: 21pt;">2）确定右边界字符串</p>
<p class="WEB" style="text-indent: 21pt;">接下来要找出动态数据的右边界字符串，这个字符串就比较好找了，从动态数据的最后一个字符开始，通常就是要找的右边界字符串。</p>
<p class="WEB" style="text-indent: 21pt;">以这个例子来看，就是&#8220;&gt;&#8221;，所以再把右边界字符串加入web_reg_save_param函数中，最后再加上&#8220;LAST);&#8221;就完成整个web_reg_save_param函数：</p>
<p class="ae" style="text-indent: 20.7pt;">web_reg_save_param("UserSession",
"LB= input type=hidden name= userSession value=",
"RB=&gt;", LAST); </p>
<p class="WEB" style="text-indent: 21pt;">当使用web_reg_save_param建立参数后，接下来就是用&#8220;UserSession&#8221;参数去取代脚本中写死的（hard-coded）资料。即将</p>
<p class="ae" style="text-indent: 20.7pt;">"Name=userSession","Value=75893.0884568651DQADHfApHDHfcDtccpfAttcf",
ENDITEM, </p>
<p class="WEB" style="text-indent: 21pt;">替换为：</p>
<p class="ae" style="text-indent: 20.7pt;">"Name=userSession",
"Value={UserSession}", ENDITEM, </p>
<p class="WEB" style="text-indent: 21pt;">至此，已经完成了一个关联了，接下来就是执行脚本，验证其是否能成功运行。假如还是有问题，就要检查看看是否还需要再做另一个关联。
</p>
<p class="WEB" style="text-indent: 21pt;">4．将脚本中有用到关联的数据，以参数取代。</p>
<p class="WEB" style="text-indent: 21pt;">利用前面所介绍的方法找到需要关联的地方，把需要变更的常量用参数进行取代，具体参数化步骤参看第3章3.2.1节的内容，在此不再赘述。</p>
<p class="WEB" style="text-indent: 21pt;">参数化的过程执行如下操作：</p>
<p class="WEB" style="text-indent: 21pt;">（1）用参数替换脚本中的常量。</p>
<p class="WEB" style="text-indent: 21pt;">（2）为参数设置属性和数据源。</p>
<p class="WEB" style="text-indent: 21pt;">参数化的过程要注意以下事项：</p>
<p class="WEB" style="text-indent: 21pt;">（1）在参数化的过程中，只有函数中的参数能被参数化，而且也不是所有函数中的参数都能参数化。例如，Lrd_stmt只能参数化mpcText。</p>
<p class="WEB" style="text-indent: 21pt;">（2）参数化CORBA或General_java Vsuer这两个地方保证完整性，必须参数化整个字符串。</p>
<p class="WEB" style="text-indent: 21pt;">（3）参数的格式要与所录制的脚本相一致，否则脚本可能不能正常运行。</p>
<h3>3.3.4&nbsp; 关联中的常见问题</h3>
<p class="WEB" style="text-indent: 21pt;">设置语句关联时，如果经验不足，经常会出现一些问题。本节将提供一些关联过程中常见的问题的解决方法，其他出现的问题需要在实际应用中具体分析和处理。</p>
<p class="WEB" style="text-indent: 21pt;">1．在脚本的data目录下找不到录制时的快照（snapshot）。</p>
<p class="WEB" style="text-indent: 21pt;">问题可能的原因如下：</p>
<p class="WEB" style="text-indent: 21pt;">（1）脚本是由VuGen
6.02或更早的版本所录制的；</p>
<p class="WEB" style="text-indent: 21pt;">（2）汇入的Action不会包含快照（snapshot）的档案；</p>
<p class="WEB" style="text-indent: 21pt;">（3）脚本存储在只读的目录下，造成VuGen无法存储执行时撷取的快照；</p>
<p class="WEB" style="text-indent: 21pt;">（4）某些步骤并不会产生快照，如浏览某个资源；</p>
<p class="WEB" style="text-indent: 21pt;">（5）快照功能被取消。</p>
<p class="WEB" style="text-indent: 21pt;">解决办法：选择&#8220;Tools&#8221;&gt;&#8220;General options&#8221;&gt;&#8220;Correlation&#8221;&gt;&#8220;Save correlation information
during replay&#8221;，开启快照（snapshot）功能。</p>
<p class="WEB" style="text-indent: 21pt;">2．开启WinDiff时出现&#8220;File no longer available&#8221;的错误信息。</p>
<p class="WEB" style="text-indent: 21pt;">问题的原因如下：WinDiff工具有限制，对于包含空格符的目录或是脚本无法开启。</p>
<p class="WEB" style="text-indent: 21pt;">解决办法：为目录或脚本命名时不要使用空格符，并且尽可能将名称取短一点。</p>
<p class="WEB" style="text-indent: 21pt;">3．录制时突然跳出&#8220;Correlation warning&#8221;对话窗口。</p>
<p class="WEB" style="text-indent: 21pt;">问题的原因如下：</p>
<p class="WEB" style="text-indent: 21pt;">如果勾选自动关联的&#8220;Issue a popup message and let me decide online&#8221;选项，当VuGen发现有可能要做关联的数据时，就会跳出&#8220;Correlation
warning&#8221;的窗口，询问要做&#8220;关联&#8221;（Correlation in script）还是要&#8220;忽略&#8221;（Ignore），如图3-26所示。</p>
<p class="3"><img  src="http://book.csdn.net/BookFiles/839/img/image159.jpg" id="图片 26" alt="Snap9" width="183" height="206"></p>
<p class="1">图3-26 关联警告</p>
<p class="WEB" style="text-indent: 21pt;">解决方法：可以勾选&#8220;Perform correlation in script&#8221;，让VuGen自动作关联，不会再跳出询问窗口；或者勾选&#8220;Disable correlation engine&#8221;，关闭自动关联的功能。</p>
<p class="WEB" style="text-indent: 21pt;">4．如何打印出参数值</p>
<p class="WEB" style="text-indent: 21pt;">解决方法：利用lr_eval_string与lr_output_message这两个函数来打印出参数值。</p>
<p class="WEB" style="text-indent: 21pt;">例子：</p>
<p class="ae" style="text-indent: 20.7pt;">lr_output_message("Value Captured=%s",lr_eval_string("{ParameterName}"));</p>
<p class="WEB" style="text-indent: 21pt;">5．如何手动启动&#8220;Scan action for
correlation&#8221;的功能</p>
<p class="WEB" style="text-indent: 21pt;">解决方法：要启用&#8220;Scan Action for Correlation&#8221;功能，请单击&#8220;Tools&#8221;&gt;&#8220;General options&#8221;&gt;&#8220;Correlation tab&#8221;，勾选&#8220;Show Scan for correlation
popup after replay of Vuser&#8221;选项。</p><img src ="http://www.cnitblog.com/stomic/aggbug/54898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/stomic/" target="_blank">大话人生</a> 2009-02-26 17:00 <a href="http://www.cnitblog.com/stomic/archive/2009/02/26/54898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>