标签:
转载:http://blog.csdn.net/fengshuiyue/article/details/42401223
最近对服务器的性能感兴趣,于是开始研究了一阵子loadrunner如何做采用TCP协议交互的服务器的性能测试,对loadrunner不是很熟悉,所以一开始也走了一些弯路,现将学习的过程记录下来,为以后做参考吧。
TCP协议的服务器的性能测试,我想大家都会选择loadrunner的winsocket协议进行测试,我也是采用此种方式。下面将逐一记录如何使用此协议做性能测试。
1.采用DLL文件方式进行测试
由于与服务器连接的客户端的DLL文件我手头有,同时其对应的头文件也有,所以一开始试想的是采用loadrunner调用DLL文件的方式来实现 性能测试。因为这种方式简单,不需了解很多loadrunner的winsocket的相关函数,容易上手。下面的代码即是采用DLL文件初步编写的代 码:
vuser_init.c
- vuser_init()
- {
- lrs_startup(257);
- lr_load_dll("InnoVSSBASClient.dll");
- lr_load_dll("ole32.dll");
- return 0;
- }
action.c
- #include "lrs.h"
- #include "def.h"
-
- Action()
- {
-
- char* test;
- long handle;
- NET_CLIENT_INFO info;
- int isLogin;
- NET_CROSS_INFO crossInfo;
- NET_VEHCILE_PASS_INFO lrPassInfo = {0};
- NET_VEHCILE_ALARM_INFO lrAlarmInfo = {0};
- handle = InnoVSSBASClient_Init(NULL,NULL);
- strcpy(info.clientId,guid_gen());
- strcpy(info.serverIP,"127.0.0.1");
- info.serverPort = 9300;
- strcpy(info.username,"admin");
- strcpy(info.password,"admin");
-
-
- lr_start_transaction("tran_login_start");
-
- isLogin = InnoVSSBASClient_CreateConn(handle,&info);
- if(isLogin==1){
- lr_end_transaction("tran_login_start", LR_AUTO);
- lr_output_message(info.clientId);
- lr_output_message("登陆成功");
-
-
-
- lr_start_transaction("tran_addcross_start");
- strcpy(crossInfo.crossId,lr_eval_string("{crossId}"));
- InnoVSSBASClient_AddCrossInfo(handle,&crossInfo);
- lr_end_transaction("tran_addcross_start", LR_AUTO);
-
- }else{
- lr_end_transaction("tran_login_start", LR_FAIL);
- lr_output_message(info.clientId);
- lr_output_message("登陆失败");
- }
-
-
-
- while(1)
- {
- sleep(100);
- }
- return 0;
- }
vuser_init中加载了程序所需要的DLL文件,InnoVSSBASClient.dll为与服务器连接的客户端的DLL文件,而ole32.dll为程序中的字符串函数(比如strcpy等)需要加载的DLL文件。
action中则是性能测试的主体代码。本代码一共对两个操作:登录和添加路口信息做了事务监控。
采用DLL文件的方式针对测试简单的顺序的操作很适用,但是本客户端还有个功能是需要处理服务器实时传输的过车等信息的功能,即在测试服务器端功能的时候,还需要模拟出客户端的回调函数的功能,但是在loadrunner中没有找到定义回调函数的方式,于是不得不放弃这种简单的性能测试的方式。在此想向loadrunner的大牛问一下,如何在loadrunner中第一回调函数呢?
上面的方式不能真实的模拟客户端的情况,于是下面会记录采用loadrunner本身的winsocket函数进行测试。
2.采用loadrunner的winsocket函数做测试
我先上源码,然后逐一讲解:
def.h //本文件是外部文件,在此用于定义自定义函数
- char* guid_gen(){
- typedef struct _GUID {
- unsigned long Data1;
- unsigned short Data2;
- unsigned short Data3;
- unsigned char Data4[8];
- } GUID;
- GUID m_guid;
- char buf[50];
- char pNameStr[50];
- CoCreateGuid(&m_guid);
-
-
-
- sprintf (buf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- m_guid.Data1, m_guid.Data2, m_guid.Data3,
- m_guid.Data4[0], m_guid.Data4[1], m_guid.Data4[2], m_guid.Data4[3],
- m_guid.Data4[4], m_guid.Data4[5], m_guid.Data4[6], m_guid.Data4[7]);
-
-
- return lr_eval_string(buf);
- }
-
- char* join(char *s1, char *s2)
- {
- char *result = (char*)malloc(strlen(s1)+strlen(s2)+1);
-
- if (result == NULL) exit (1);
-
- strcpy(result, s1);
- strcat(result, s2);
-
- return result;
- }
-
- void Substitute(char *pInput, char *pOutput, char *pSrc, char *pDst)
- {
- char *pi, *po, *p;
- int nSrcLen, nDstLen, nLen;
-
-
- pi = pInput;
-
- po = pOutput;
-
- nSrcLen = strlen(pSrc);
- nDstLen = strlen(pDst);
-
-
- p = (char*)strstr(pi, pSrc);
- if(p)
- {
-
- while(p)
- {
-
- nLen = (int)(p - pi);
-
- memcpy(po, pi, nLen);
- memcpy(po + nLen, pDst, nDstLen);
-
- pi = p + nSrcLen;
-
- po = po + nLen + nDstLen;
-
- p = (char*)strstr(pi, pSrc);
- }
-
- strcpy(po, pi);
- }
- else
- {
-
- strcpy(po, pi);
- }
- }
-
- char *strreplace(char *dest, char *src, const char *oldstr, const char *newstr, size_t len)
- {
-
- char *needle;
-
- char *tmp;
-
-
- lr_output_message("newStr:%s",newstr);
- if(strcmp(oldstr, newstr)==0)
- {
- return src;
- }
-
-
- dest = src;
-
- while((needle = (char *) strstr(dest, oldstr)) && (needle -dest <= len))
- {
-
- tmp=(char*)malloc(strlen(dest)+(strlen(newstr)-strlen(oldstr))+1);
-
- strncpy(tmp, dest, needle-dest);
-
- tmp[needle-dest]=‘\0‘;
-
- strcat(tmp, newstr);
-
- strcat(tmp, needle+strlen(oldstr));
-
- dest = (char *)strdup(tmp);
-
- free(tmp);
- }
- return dest;
- }
本文件包含了两种功能的函数:一个是如何生成guid,一个是如何替换字符串中的子串。
action.c
-
- #include "lrs.h"
- #include "def.h"
-
- Action()
- {
- int sendLoginCount=0,sendCrossCount=0;
- int loginIndex,loginIndex2;
- char* clientId = guid_gen();
- char clientId2[100];
- char* clientId3;
- int clientIdlen;
- char* loginSrc = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<Parament>\n"
- " <ClientId>$ClientId</ClientId>\n"
- " <ServerIP>$IP</ServerIP>\n"
- " <ServerPort>$Port</ServerPort>\n"
- " <Username></Username>\n"
- " <Password></Password>\n"
- "</Parament>";
- char* loginStr;
- int loginStrLen;
- char* loginStrLenHex;
- char loginStrLenStr[5];
- char send_loginHeader[100]="\\x12$Len\\x00\\x010";
- char* send_loginHeaderf;
- char send_loginStr[1500]="";
-
-
-
- char* crossSrc= "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<Parament>\n"
- " <ClientId>$ClientId</ClientId>\n"
- " <CrossId>$CrossId</CrossId>\n"
- "</Parament>";
- char* send_addCrossHeader = "\\x12$Len\\x00\\x02";
- char* crossId = lr_eval_string("<db_crossId>");
- char* crossStr;
- char send_crossStr[1700];
- char crossStrLenStr[5];
- int crossStrLen;
- char* send_addCrossHeaderf;
- int crossAddIndex,crossAddIndex2;
-
- strcpy(clientId2,lr_eval_string(clientId));
- clientId3 = clientId;
-
-
-
- loginStr = strreplace(loginStr,loginSrc,"$ClientId",clientId,strlen(loginSrc));
- loginStr = strreplace(loginStr,loginStr,"$IP","127.0.0.1",strlen(loginStr));
- loginStr = strreplace(loginStr,loginStr,"$Port","9300",strlen(loginStr));
- lr_output_message("loginStr:%s",loginStr);
-
- loginStrLen = strlen(loginStr)+1;
-
-
- sprintf(loginStrLenStr, "%X", loginStrLen);
-
- if(strlen(loginStrLenStr)==2)
- {
- char tmpH[5];
- strcpy(tmpH,loginStrLenStr);
- strcpy(loginStrLenStr,"\\x00\\x00\\x00\\x");
- strcat(loginStrLenStr,tmpH);
- }else{
- char tmpH[5];
- char tmpD[5];
- strcpy(tmpH,loginStrLenStr);
- strcpy(tmpH+1,"\0");
- strcpy(tmpD,loginStrLenStr+strlen(loginStrLenStr)-2);
- strcpy(loginStrLenStr,"\\x00\\x00\\x0");
- strcat(loginStrLenStr,tmpH);
- strcat(loginStrLenStr,"\\x");
- strcat(loginStrLenStr,tmpD);
-
-
- }
-
-
- send_loginHeaderf = strreplace(send_loginHeaderf,send_loginHeader,"$Len",loginStrLenStr,strlen(send_loginHeader));
-
- strcpy(send_loginStr,send_loginHeaderf);
-
-
-
- for(loginIndex=0,loginIndex2=strlen(send_loginStr);loginIndex<strlen(loginStr);loginIndex++,loginIndex2++)
- {
- char loginHex[5];
- sprintf(loginHex,"\\x%.2X",loginStr[loginIndex]);
-
- strcat(send_loginStr+loginIndex2,loginHex);
- }
- strcat(send_loginStr+loginIndex2,"\\x0A");
- lr_output_message("send_loginStr:%s",send_loginStr);
-
-
-
- lr_start_transaction("login");
- lrs_create_socket("socket0", "TCP", "LocalHost=0", "RemoteHost=127.0.0.1:1234",LrsLastArg);
- for(sendLoginCount = 0;sendLoginCount < 10;sendLoginCount++)
- {
-
- lr_output_message("sendLoginCount:%d",sendLoginCount);
- lrs_set_send_buffer("socket0",send_loginStr,strlen(send_loginStr));
- lrs_send("socket0","buf0",LrsLastArg);
- lrs_receive("socket0", "buf1", LrsLastArg);
- {
- char* login_recv;
- int login_recvlen;
- int i;
- lrs_get_last_received_buffer("socket0",&login_recv,&login_recvlen);
- if(login_recvlen!=0)
- {
- lr_end_transaction("login", LR_AUTO);
- lr_output_message("%s",login_recv+15);
-
-
-
- lr_output_message("clientId3:%s",lr_eval_string(clientId2));
- crossStr = strreplace(crossStr,crossSrc,"$ClientId",clientId3,strlen(crossSrc));
- crossStr = strreplace(crossStr,crossStr,"$CrossId",crossId,strlen(crossStr));
- lr_output_message("crossStr:%s",crossStr);
- crossStrLen = strlen(crossStr)+1;
- sprintf(crossStrLenStr,"%X",crossStrLen);
- if(strlen(crossStrLenStr)==2)
- {
- char tmpH[5];
- strcpy(tmpH,crossStrLenStr);
- strcpy(crossStrLenStr,"\\x00\\x00\\x00\\x");
- strcat(crossStrLenStr,tmpH);
- }else{
- char tmpH[5];
- char tmpD[5];
- strcpy(tmpH,crossStrLenStr);
- strcpy(tmpH+1,"\0");
- strcpy(tmpD,crossStrLenStr+strlen(crossStrLenStr)-2);
- strcpy(crossStrLenStr,"\\x00\\x00\\x0");
- strcat(crossStrLenStr,tmpH);
- strcat(crossStrLenStr,"\\x");
- strcat(crossStrLenStr,tmpD);
-
-
- }
-
-
- send_addCrossHeaderf = strreplace(send_addCrossHeaderf,send_addCrossHeader,"$Len",crossStrLenStr,strlen(send_addCrossHeader));
-
- strcpy(send_crossStr,send_addCrossHeaderf);
-
-
- for(crossAddIndex=0,crossAddIndex2=strlen(send_crossStr);crossAddIndex<strlen(crossStr);crossAddIndex++,crossAddIndex2++)
- {
- char crossHex[5];
- sprintf(crossHex,"\\x%.2X",crossStr[crossAddIndex]);
-
- strcat(send_crossStr+crossAddIndex2,crossHex);
- }
- strcat(send_crossStr+crossAddIndex2,"\\x0A");
- lr_output_message("send_crossStr:%s",send_crossStr);
-
-
- lr_start_transaction("addCross");
- for(sendCrossCount=0;sendCrossCount<10;sendCrossCount++)
- {
- lr_output_message("send_crossStr:%s",send_crossStr);
- lr_output_message("sendCrossCount:%d",sendCrossCount);
- lrs_set_send_buffer("socket0",send_crossStr,strlen(send_crossStr));
- lrs_send("socket0","buf0",LrsLastArg);
- lrs_receive("socket0","buf1",LrsLastArg);
-
- {
- char* cross_recv;
- int cross_recvlen;
- lrs_get_last_received_buffer("socket0",&cross_recv,&cross_recvlen);
-
- if(cross_recvlen!=0)
- {
- lr_end_transaction("addCross", LR_AUTO);
- lr_output_message("cross_recv:%s",cross_recv+15);
- break;
- }else{
-
- }
-
- }
- }
- if(sendCrossCount>10)
- {
- lr_end_transaction("addCross", LR_FAIL);
- }
-
- break;
-
- }else{
-
- }
-
- }
- }
-
-
- if(sendLoginCount>10)
- {
- lr_end_transaction("login", LR_FAIL);
- }
-
- while(1)
- {
- char* recv;
- int recvlen;
-
- lrs_receive("socket0","buf3",LrsLastArg);
- lrs_get_last_received_buffer("socket0",&recv,&recvlen);
-
- if(recvlen!=0)
- {
- lr_output_message("recv:%s",recv+15);
- }else{
-
- }
-
- }
-
- lrs_close_socket("socket0");
-
- return 0;
- }
上面代码的具体业务就不介绍了,在此我介绍一下在该片代码中应该注意的地方:
1)本代码模拟了客户端所发的16进制的数据,在此提一下字符、字符串如何转换成loadrunner中的16进制的字符串。
在loadrunner中16进行的字符采用前面加’\x‘的方式表示,如16进制0xAB,则在loadrunner中需要表示为‘\xAB‘;
整形转为16进制字符串:sprintf(loginStrLenStr, "%X", loginStrLen);
16进制字符串转换为loadrunner中认可的16进制串:
- for(loginIndex=0,loginIndex2=strlen(send_loginStr);loginIndex<strlen(loginStr);loginIndex++,loginIndex2++)
- {
- char loginHex[5];
- sprintf(loginHex,"\\x%.2X",loginStr[loginIndex]);
-
- strcat(send_loginStr+loginIndex2,loginHex);
- }
本部分使用的是本方法,即将字符串“abcd"的的每个字符逐一转换成loadrunner认可的16进制串(如:字符”a"转换成"\x61“)
该方法是个笨方法,不知在loadrunner中有没有自带的函数做字符串的16进制转换呢?
2)loadrunner做winsocket测试的基本步骤:
-
- #include "lrs.h"
-
-
- Action()
- {
- int i;
- char *buffer;
- int numberOfBytes;
-
-
- lrs_create_socket("socket0", "TCP", "LocalHost=0", "RemoteHost=127.0.0.1:1234",LrsLastArg);
-
- lr_start_transaction("send");
-
- lrs_send("socket0", "buf1", LrsLastArg);
-
-
- lrs_send("socket0", buffer, LrsLastArg);
-
-
- lrs_receive("socket0", "buf2", LrsLastArg);
-
-
- lrs_get_buffer_by_name("buf2", &buffer, &numberOfBytes);
-
- lr_output_message("The buffer‘s size is: %d/n", numberOfBytes);
- lr_output_message(buffer);
-
- lr_end_transaction("send", LR_AUTO);
-
-
-
- lrs_close_socket("socket0");
-
- return 0;
- }
上面的代码的注释很明确了,不过需要注意一点的是,loadrunner中lrs_send中的缓存的buf需要在data.ws中定义,不能是程序中定义的字符串。
data.ws
- ;WSRData 2 1
-
- send buf0
- recv buf1 101
- recv buf2 210
- recv buf3 300
-
- -1
3)对winsocket编程的一些函数的解释
①lrs_set_send_buffer("socket0",send_loginStr,strlen(send_loginStr));
lrs_set_send_buffer将程序中定义的字符串放入data.ws第一个定义的send bufx中,如上面的data.ws中定义的为buf0,则是将其方式buf0中,不管调用多少次,都是放入到buf0中。
②lrs_receive("socket0", "buf1", LrsLastArg);
lrs_get_last_received_buffer("socket0",&login_recv,&login_recvlen);
buf1定义的长度与实际接收的长度不一致没关系,loadrunner只会在输出中输出一个警告信息,但是不会影响实际接收的数据。警告信息
为: Mismatch in buffer‘s length (expected 101 bytes, 222 bytes actually
received, difference in 121 bytes)
loadrunner测试TCP协议服务器性能
标签:
原文地址:http://www.cnblogs.com/zhengah/p/4838367.html