电竞比分网-中国电竞赛事及体育赛事平台

分享

LoadRunner中winsocket協(xié)議腳本回放時(shí)的mismatch問(wèn)題處理方法

 月影曉風(fēng) 2014-08-09

使用LoadRunner錄制socket協(xié)議的腳本,會(huì)發(fā)現(xiàn)每個(gè)請(qǐng)求都會(huì)發(fā)送和接受一定長(zhǎng)度的數(shù)據(jù)流,即send buffer和recv buffer;這兩個(gè)buffer后面都會(huì)有個(gè)數(shù)字,這個(gè)數(shù)字表示buffer的長(zhǎng)度,是一個(gè)固定的值。當(dāng)做性能測(cè)試時(shí),執(zhí)行每次請(qǐng)求響應(yīng)的數(shù)據(jù)很多時(shí)候是不定長(zhǎng)的,如果recv buffer的長(zhǎng)度與響應(yīng)的數(shù)據(jù)長(zhǎng)度不一致,腳本會(huì)報(bào)錯(cuò),有兩種方法可以解決這個(gè)問(wèn)題:

1、造數(shù)據(jù),使響應(yīng)的數(shù)據(jù)長(zhǎng)度在每次不同請(qǐng)求中都一樣。但實(shí)際上,方法1是有局限性的,也就是說(shuō)有些請(qǐng)求通過(guò)造數(shù)據(jù)也不能使響應(yīng)的數(shù)據(jù)長(zhǎng)度一致,那么我們可以采用方法2。

2、自定義函數(shù),動(dòng)態(tài)解析并接受不定長(zhǎng)響應(yīng)數(shù)據(jù)流。

以下詳細(xì)介紹下方法2,以舉例講解的方式來(lái)介紹:

【業(yè)務(wù)場(chǎng)景】:用戶進(jìn)行登錄操作,每次登錄的響應(yīng)數(shù)據(jù)由于被加密壓縮后才返回的緣故,導(dǎo)致長(zhǎng)度不一致。

【協(xié)議簡(jiǎn)介】:用戶登錄操作采取的協(xié)議是自定義協(xié)議,協(xié)議頭中第5,6個(gè)byte保存的是整個(gè)響應(yīng)流的長(zhǎng)度。

【自定義函數(shù)的思路】:先接受響應(yīng)數(shù)據(jù)中的前6個(gè)bytes,然后取5,6位上的字節(jié)轉(zhuǎn)換成int類(lèi)型,得到整個(gè)響應(yīng)流的長(zhǎng)度,從而計(jì)算出剩下未被接受的數(shù)據(jù)長(zhǎng)度,再接受剩下的數(shù)據(jù)。

【代碼實(shí)現(xiàn)】:

 第一部分,錄制后未經(jīng)修改的腳本如下:

Action()
{
lr_start_transaction("login");

     lrs_create_socket("socket6", "TCP", "RemoteHost=172.16.4.16:1122",  LrsLastArg);

// 登錄請(qǐng)求
lr_think_time(5);
    lrs_send("socket6", "buf1", LrsLastArg);

lrs_receive("socket6", "buf2", LrsLastArg);
       
    lrs_close_socket("socket6");

lr_end_transaction("login", LR_AUTO);

    return 0;
}
  

send  buf1 49
"\x00\x00"
"??"
"\x00"
"1"
"\x00"
" "
"\xc2"
"\t"
"\x00\xa7\xff\xd3\x00\x00\x00"
"\n"
"<fname>"
"\x00\xa7\xff\xd4\x00\x00\x00"
"\r"
"\x00\x00"
"1"
"\x00"
"2"
"\x00"
"3"
"\x00"
"4"
"\x00"
"5"
"\x00"
"6"

recv  buf
2 291           //每次請(qǐng)求的響應(yīng)數(shù)據(jù)長(zhǎng)度不一定是291個(gè)字節(jié)

【上述腳本的問(wèn)題】:

recv buf2 291 后面的這個(gè)數(shù)字表示收到的buffer長(zhǎng)度,這個(gè)長(zhǎng)度在這里就固定死了,也就說(shuō)每次執(zhí)行這個(gè)腳本的時(shí)候都會(huì)按這個(gè)長(zhǎng)度來(lái)接受解析響應(yīng)數(shù)據(jù),如果實(shí)際的響應(yīng)數(shù)據(jù)長(zhǎng)度與這個(gè)長(zhǎng)度不一致會(huì)報(bào)以下錯(cuò)誤:

Action.c(xx): Mismatch in buffer's length (expected 291 bytes, 295 bytes actually received, difference in 4 bytes)


第二部分,自定義函數(shù)和錄制后修改的腳本如下:

為了能夠動(dòng)態(tài)接收響應(yīng)數(shù)據(jù),我們自定義了一個(gè)接收函數(shù),如下:

  #include "lrs.h"

/*******************************************************************************

*自定義函數(shù),用于動(dòng)態(tài)接受返回的buffer

*0-6個(gè)字節(jié)是協(xié)議頭的一部分,5-6個(gè)字節(jié)是整個(gè)響應(yīng)包的長(zhǎng)度

* 1.首先接受6個(gè)字節(jié),并解析出第5,6個(gè)字節(jié);

* 2. 計(jì)算出整個(gè)響應(yīng)包的長(zhǎng)度:length,并計(jì)算出剩下的長(zhǎng)度:length-6;

* 3. 接受剩下的數(shù)據(jù)流;

********************************************************************************/
int custom_lrs_receive(char *sock_desc, char *buf_desc,void *dummy)
{
int rc;

int buf_len = 6;

char szBytesLength[30], *buf = NULL, *pszError, *pszLastChar;

/* 
* Get package header  0-6個(gè)bytes, [5..6] bytes  is package length 
*/

rc = lrs_receive_ex(sock_desc, buf_desc, "NumberOfBytesToRecv=6", LrsLastArg);

if (rc != 0)     //正常情況下函數(shù)返回為0,非0表示函數(shù)有錯(cuò)誤
{
lr_error_message("Receive 6 bytes failed. The error code = %d", rc);

return -1;

} /* Receive failed */


//判斷前6個(gè)字節(jié)是否接受成功

lrs_get_last_received_buffer(sock_desc, &buf, &buf_len);

if (buf == NULL || buf_len != 6)
{
lr_error_message("receive of %s failed", buf_desc);

return -1;
}

/* Compute buffer length */
sprintf (szBytesLength, "NumberOfBytesToRecv=%d", fiFromHexBinToInt(buf) - 6);            //調(diào)用另一個(gè)自定義函數(shù):計(jì)算總長(zhǎng)度的函數(shù)

lr_debug_message(LR_MSG_CLASS_FULL_TRACE, "!!!! Bytes length = %s", szBytesLength);


/* 接受剩下的字節(jié)流 */
rc = lrs_receive_ex(sock_desc, buf_desc, szBytesLength, LrsLastArg);

if (rc != 0) /* Receive failed */
return -1;

return 0;
}


/* 
* 解析szBuffer中的5-6個(gè)字節(jié),并轉(zhuǎn)換成int類(lèi)型
*/
int fiFromHexBinToInt(char *szBuffer)
{
int i, j, iIntValue = 0, iExp = 1; 
/*lr_output_message("the szBuffer is %d %d", 
szBuffer[5] & 0x000000ff,((szBuffer[6] & 0x000000ff));*/

for( i = 1; i >= 0; i--)      //一個(gè)字節(jié)一個(gè)字節(jié)的取值,循環(huán)2次,分別取第6位,第5位上的字節(jié)
{
iExp = 1;

for (j = 2; j > i*2; j--)    //從16進(jìn)制字節(jié)流轉(zhuǎn)換成int類(lèi)型:2個(gè)byte4個(gè)bit,每個(gè)字節(jié)的低位分別需要乘以16的0次方和16的2次方;

iExp *= 16;

iIntValue += (szBuffer[i+4] & 0x0000000f) * iExp + ((szBuffer[i+4] & 0x000000f0) >> 4) * iExp * 16;

lr_output_message("the length is %d", iIntValue);

return iIntValue;
}

/*********************************************************************
*修改后的 測(cè)試腳本
*********************************************************************/
Action()
{
lr_start_transaction("login");

    lrs_create_socket("socket6", "TCP", "RemoteHost=172.16.4.16:1122",  LrsLastArg);

// 登錄請(qǐng)求
lr_think_time(5);
     lrs_send("socket6", "buf1", LrsLastArg);

        custom_lrs_receive("socket6", "buf2", LrsLastArg);    //自定義函數(shù)接受不定長(zhǎng)數(shù)據(jù)流

     lrs_close_socket("socket6");

lr_end_transaction("login", LR_AUTO);

    return 0;

}


這樣就ok了。對(duì)于使用這套協(xié)議的所有接口,該自定義函數(shù)可通用。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多