|
使用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()
lrs_receive("socket6", "buf2", LrsLastArg);
send buf1 49 【上述腳本的問(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);
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ù)可通用。
|
|
|
來(lái)自: 月影曉風(fēng) > 《問(wèn)題匯總》