array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 用LoadRunner编写socket应用的测试脚本 - 爱码网
        LoadRunner提供了很好的对socket应用的支持,用户可以通过录制方法完全获得客户端发送和接收的数据,然后在录制的基础上对相应的数据进行参数化和关联等处理。

        但在有些情况下(例如,客户端程序没有windows上的版本),我们就很难通过录制达成生成脚本的目标了。但如果我们能够完全知晓服务端和客户端的交互过程,完全手工编写一个测试脚本也并不是一件特别困难的事情。

       在本文中,我们以一个实际的例子说明如何根据服务端和客户端交互的过程,用LoadRunner自行编写相应的脚本。

        以下是服务端工作线程的代码:
DWORD WINAPI mythread( LPVOID lpParameter)    //客户线程
{
    
struct My my;
    memcpy(
&my,lpParameter,sizeof(My));    
    printf(
"One client connect!\n");
    
char str1[1024];            //接收字符串
    char str2[1024];
                        
    
int i;
    i
=recv(my.skt,str1,sizeof(str1),0);    //接收客户请求
    str1[i]=0;

    
char *filename;
    filename
=new char[255];
    
for(int j=2;j<i;j++)            //获得文件名
    {
        filename[j
-2]=str1[j];
    }
    filename[i
-2]=0;
   

    
if (str1[0]=='S')
    {
        printf(
"The file name : %s\n",filename);
        ofstream 
out(filename);                //创文件流   
        if (!out)
        {
            printf(
"cannot open file.\n");        //文件是否正确打开,打开错误则退出
            send(my.skt,"q",1,0);            //向客户发送退出信息
            closesocket(my.skt);            //解除客户连接;
            return 0;
        }
        str2[
0]='O';                       
        str2[
1]='K';
        str2[
2]=0;
        send(my.skt,str2,strlen(str2),
0);        //回复OK信息

        i
=recv(my.skt,str1,sizeof(str1),0);        //接收文件长度
        str1[4]=0;
       
        
int len;
        len
=str1[0]*1000+str1[1]*100+str1[2]*10+str1[3];
        printf(
"The File lenght is: %d Byte\n",len);
       
        
for(int j=0;j<len;j++)
            {
                
char str[1];
                i
=recv(my.skt,str,sizeof(str),0);//接收文件,按字节接收,接收字符串为2个字节
                str[i]=0;
                
out.put(str[0]);
            }

        
out.close();                    //关闭文件
        printf("over!One client quit!\n");        //接收文件完毕
        closesocket(my.skt);                //解除此客户连接
        return 0;
    }

    
if (str1[0]=='R')
    {       
       
        ifstream 
in(filename);
        
if (!in)
        {
            printf(
"cannot open file or file not exist.\n");    //文件是否正确打开,打开错误则退出
            send(my.skt,"q",1,0);                    //向客户发送退出信息
            closesocket(my.skt);                    //解除客户连接;
            return 0;
        }
        
char ch;
        
int len=0;
        
while(in.get(ch))
        {
            len
++;                            //get file lenght
        }
        
in.close();
        str2[
0]='O';
        str2[
1]='K';
        str2[
2]=len/1000;                       
        str2[
3]=(len%1000)/100;
        str2[
4]=(len%100)/10;
        str2[
5]=len%10;
        printf(
"%s",str2);
        send(my.skt,str2,
6,0);                        //发OK+文件长度

        
in.open(filename);
        
if (!in)
        {
            printf(
"cannot open file or file not exist.\n");    //文件是否正确打开,打开错误则退出
            send(my.skt,"q",1,0);                    //向客户发送退出信息
            closesocket(my.skt);                    //解除客户连接;
            return 0;
        }

        
while(in.get(ch))                        //发文件
        {               
            
char str[1];
            strcpy(str,
"");
            str[
0]=ch;
            str[
1]=0;
            send(my.skt,str,
1,0);                    //发送一个字符
        }
        
in.close();
        printf(
"over,One client quit!\n");                //传输文件完毕
        closesocket(my.skt);                        //解除此客户连接
        return 0;
    }

    printf(
"Bad command!\n");
    closesocket(my.skt);
    
return 0;
}

        从这段代码中可以看到,当客户端和服务端建立连接后,客户端会先向服务端发送一个请求,该请求的第一个字节是大写的“S”或是“R”,分别向服务端写文件或是从服务端读取文件。从第三个字节开始,后面的内容是请求文件的文件名。

        服务端在接收到客户端的请求后,根据请求的类型,如果是“S”,则打开指定的文件,并返回一个字符串“OK”;如果是“R”,则打开指定的文件并向客户端发送“OK”+“文件长度”。

        随后,如果是“S”,则由客户端发送写入的文件长度和文件内容给服务端;如果是“R”,则向客户端发送文件的内容。

        到此我们已经完全明了了客户端和服务端的交互过程,因此,我们可以尝试在LR中建立一个脚本用户模拟客户端行为。

        下面我们以“S”的处理过程为例编写脚本。

        1、打开VUGen应用;
        2、新建脚本,选择“windows sockets”协议,不需录制;
        3、在Action Section中增加以下内容:
    //建立到服务端的连接
    lrs_create_socket("socket1","TCP","RemoteHost=127.0.0.1:8000",LrsLastArg);
   
    
//发送“S”和文件名
    lrs_send("socket1""buf0", LrsLastArg);
    lrs_receive(
"socket1""buf1", LrsLastArg);
   
    
//发送要写入的数据的长度
    lrs_send("socket1""buf2", LrsLastArg);

    
//发送数据内容
    lrs_send("socket1""buf3", LrsLastArg);
   
    
//关闭连接
    lrs_close_socket("socket1");
   
        4、这样就成功的描述了整个交互过程,但还没有给出实际要发送的数据。在采用“Windows Sockets”协议的脚本中,实际发送的数据存放在data.ws Section中,因此,打开该Section,直接输入:
send  buf0 7
    
"S"
    
"\x00"
    
"1.txt"

recv buf1 
2
    
"OK"

send buf2 
3
    
"\x00"
    
"\x00"
    
"\x02"
    
"\x00"

send buf3 
20
    
"12345678901234567890"

        每个发送和接收的数据包在这里都有登记,“send”和“recv”表示数据的方向;“buf0”等表示数据包的描述,和脚本中的内容对应;接下来的一个整数表示数据包的长度;然后是数据包的内容,“\x00”表示16进制的00。

        该脚本描述了客户端向服务端请求写入一个文件1.txt,文件内容为“12345678901234567890”的过程。

        以下是脚本和服务端程序(可执行文件)的下载链接,读者可以下载到本地自行试验。

       下载服务端程序

       下载脚本

       ==========================================================================
       更多精彩LoadRunner文章,请见 关河@与谁同坐轩 LoadRunner栏目

 

相关文章: