使用LoadRunner錄制socket協(xié)議的腳本,會發(fā)現(xiàn)每個請求都會發(fā)送和接受一定長度的數(shù)據(jù)流,即send buffer和recv buffer;這兩個buffer后面都會有個數(shù)字,這個數(shù)字表示buffer的長度,是一個固定的值。當做性能測試時,執(zhí)行每次請求響應的數(shù)據(jù)很多時候是不定長的,如果recv buffer的長度與響應的數(shù)據(jù)長度不一致,腳本會報錯,有兩種方法可以解決這個問題: 1、造數(shù)據(jù),使響應的數(shù)據(jù)長度在每次不同請求中都一樣。但實際上,方法1是有局限性的,也就是說有些請求通過造數(shù)據(jù)也不能使響應的數(shù)據(jù)長度一致,那么我們可以采用方法2。 2、自定義函數(shù),動態(tài)解析并接受不定長響應數(shù)據(jù)流。 以下詳細介紹下方法2,以舉例講解的方式來介紹: 【業(yè)務場景】:用戶進行登錄操作,每次登錄的響應數(shù)據(jù)由于被加密壓縮后才返回的緣故,導致長度不一致。 【協(xié)議簡介】:用戶登錄操作采取的協(xié)議是自定義協(xié)議,協(xié)議頭中第5,6個byte保存的是整個響應流的長度。 【自定義函數(shù)的思路】:先接受響應數(shù)據(jù)中的前6個bytes,然后取5,6位上的字節(jié)轉(zhuǎn)換成int類型,得到整個響應流的長度,從而計算出剩下未被接受的數(shù)據(jù)長度,再接受剩下的數(shù)據(jù)。 【代碼實現(xiàn)】: 第一部分,錄制后未經(jīng)修改的腳本如下:
Action()
lrs_receive("socket6", "buf2", LrsLastArg);
send buf1 49 【上述腳本的問題】: recv buf2 291 后面的這個數(shù)字表示收到的buffer長度,這個長度在這里就固定死了,也就說每次執(zhí)行這個腳本的時候都會按這個長度來接受解析響應數(shù)據(jù),如果實際的響應數(shù)據(jù)長度與這個長度不一致會報以下錯誤: Action.c(xx): Mismatch in buffer's length (expected 291 bytes, 295 bytes actually received, difference in 4 bytes)
第二部分,自定義函數(shù)和錄制后修改的腳本如下: 為了能夠動態(tài)接收響應數(shù)據(jù),我們自定義了一個接收函數(shù),如下:
#include "lrs.h" /********************************************************************************自定義函數(shù),用于動態(tài)接受返回的buffer *0-6個字節(jié)是協(xié)議頭的一部分,5-6個字節(jié)是整個響應包的長度 * 1.首先接受6個字節(jié),并解析出第5,6個字節(jié); * 2. 計算出整個響應包的長度:length,并計算出剩下的長度: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個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ù)有錯誤 { lr_error_message("Receive 6 bytes failed. The error code = %d", rc); return -1; } /* Receive failed */
//判斷前6個字節(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)用另一個自定義函數(shù):計算總長度的函數(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個字節(jié),并轉(zhuǎn)換成int類型 */ 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--) //一個字節(jié)一個字節(jié)的取值,循環(huán)2次,分別取第6位,第5位上的字節(jié) { iExp = 1; for (j = 2; j > i*2; j--) //從16進制字節(jié)流轉(zhuǎn)換成int類型:2個byte4個bit,每個字節(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; } /********************************************************************* *修改后的 測試腳本 *********************************************************************/ Action() { lr_start_transaction("login"); lrs_create_socket("socket6", "TCP", "RemoteHost=172.16.4.16:1122", LrsLastArg); // 登錄請求 lr_think_time(5); lrs_send("socket6", "buf1", LrsLastArg); custom_lrs_receive("socket6", "buf2", LrsLastArg); //自定義函數(shù)接受不定長數(shù)據(jù)流 lrs_close_socket("socket6"); lr_end_transaction("login", LR_AUTO); return 0; }
這樣就ok了。對于使用這套協(xié)議的所有接口,該自定義函數(shù)可通用。
|
|