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”的過程。