2012年2月6日 星期一

用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

沒有留言: