天天看點

利用LoadRunner編寫socket性能測試腳本

一、概述

  二、socket概述

  目前常用的socket,最早起源于BSD UNIX類的作業系統。在UNIX系統上,比如BSD,把對網絡的支援加入作業系統,以一種擴充現有檔案描述符(後注)結構的方法來實作的。Socket 可以被看成一個标準的檔案描述符。在 UNIX 類的平台上,其中包括open()、read()、write()和close()。很多時間,程式并不需要知道它正在把資料寫進一個檔案、終端、或是一個TCP連接配接。

  系統調用被加入并和socket一起工作,而很多現有的系統調用同樣能和socket一起工作。是以,一個socket允許您使用标準的作業系統和其他的計算機,以及您自己機器上的不同程序來通信。

  然而,socket的确存在一些不同工作方式。最明顯地就是建立socket的方法。很多檔案是通過調用open()函數來打開的,但socket是通過調用socket()函數來建立的,并且還需要另外的調用來連接配接和激活他們。recv()和send()這兩個系統調用和read()和write()極為相似。

  Socket是一套建立在TCP/IP協定上的接口不是一個協定,隻要底層實作TCP IP協定,都可以用socket進行通信。

  應用層: HTTP FTP SMTP Web

  傳輸層: 在兩個應用程式之間提供了邏輯而不是實體的通信基于流的TCP和基于資料包的UDP

  檔案描述符一般是指一個檔案或某個類似檔案的實體。核心(kernel)利用檔案描述符(file descriptor)來通路檔案。檔案描述符是非負整數。打開現存檔案或建立檔案時,核心會傳回一個檔案描述符。讀寫檔案也需要使用檔案描述符來指定待讀寫的檔案。

  三、SOCKET連接配接過程

  根據連接配接啟動的方式以及本地套接字要連接配接的目标,套接字之間的連接配接過程可以分為三個步驟:伺服器監聽,用戶端請求,連接配接确認。

  伺服器監聽:是伺服器端套接字并不定位具體的用戶端套接字,而是處于等待連接配接的狀态,實時監控網絡狀态。

  用戶端請求:是指由用戶端的套接字提出連接配接請求,要連接配接的目标是伺服器端的套接字。為此,用戶端的套接字必須首先描述它要連接配接的伺服器的套接字,指出伺服器端套接字的位址和端口号,然後就向伺服器端套接字提出連接配接請求。

  連接配接确認:是指當伺服器端套接字監聽到或者說接收到用戶端套接字的連接配接請求,它就響應用戶端套接字的請求,建立一個新的線程,把伺服器端套接字的描述發給用戶端,一旦用戶端确認了此描述,連接配接就建立好了。而伺服器端套接字繼續處于監聽狀态,繼續接收其他用戶端套接字的連接配接請求。

  四、開發原理

  伺服器:使用ServerSocket監聽指定的端口,端口可以随意指定(由于1024以下的端口通常屬于保留端口,在一些作業系統中不可以随意使用,是以建議使用大于1024的端口),等待客戶連接配接請求,客戶連接配接後,會話産生;在完成會話後,關閉連接配接。

  用戶端:使用Socket對網絡上某一個伺服器的某一個端口發出連接配接請求,一旦連接配接成功,打開會話;會話完成後,關閉Socket。用戶端不需要指定打開的端口,通常臨時的、動态的配置設定一個1024以上的端口。

  Socket接口是TCP/IP網絡的API,Socket接口定義了許多函數或例程,程式員可以用它們來開發TCP/IP網絡上的應用程式。要學Internet上的TCP/IP網絡程式設計,必須了解Socket接口。Socket接口設計者最先是将接口放在Unix作業系統裡面的。如果了解Unix系統的輸入和輸出的話,就很容易了解Socket了。網絡的Socket資料傳輸是一種特殊的I/O,Socket也是一種檔案描述符。Socket也具有一個類似于打開檔案的函數調用Socket(),該函數傳回一個整型的Socket描述符,随後的連接配接建立、資料傳輸等操作都是通過該Socket實作的。

  五、Loadrunner中socket相關函數淺析

  當我們打開Create/Edit Scripts,并打開腳本錄制頁面時,摁下F1便可打開《HP LoadRunner Online Function Reference》。在這幫助文檔中找到“鍵入關鍵字進行查找”輸入框。利用它查找我們所需的socket函數了。

  幾乎所有關于socket的函數,都是以lrs開頭的。

基本操作函數:

lrs_startup 初始化 WinSock DLL

lrs_create_socket 初始化套接字

lrs_send 在資料報上(UDP)或者向流套接字(TCP)發送資料

lrs_receive 接收來自資料報或流套接字的資料

lrs_disable_socket 禁用套接字操作

lrs_close_socket 關閉打開的套接字

lrs_cleanup 終止 WinSock DLL 的使用,回收相關資源。VuGen 在 Windows 上使用 Windows 套接字協定支援應用程式的錄制和回放;而在UNIX 平台上僅支援回放

lrs_accept_connection 接受偵聽套接字連接配接

lrs_exclude_socket 重播期間排除套接字

lrs_get_socket_attrib 擷取套接字屬性

lrs_get_socket_handler 擷取指定套接字的套接字處理程式

lrs_length_receive 接收來自指定長度的緩沖區的資料

lrs_receive 接收來自套接字的資料

lrs_receive_ex 接收來自資料報或流套接字的資料(具有特定長度)

lrs_send 将資料發送到資料報上或流套接字中

lrs_set_receive_option 設定套接字接收選項

lrs_set_socket_handler 設定特定套接字的套接字處理程式

lrs_set_socket_options 設定套接字選項

  緩沖區函數:

lrs_free_buffer 釋放配置設定給緩沖區的記憶體

lrs_get_buffer_by_name 從資料檔案中擷取緩沖區及其大小

lrs_get_last_received_buffer 擷取套接字上接收到的最後的緩沖區及其大小

lrs_get_last_received_buffer_size 擷取套接字上接收到的最後一個緩沖區的大小

lrs_get_received_buffer 擷取最後接收到的緩沖區或其一部分

lrs_get_static_buffer 擷取靜态緩沖區或其一部分

lrs_get_user_buffer 擷取套接字的使用者資料的内容

lrs_get_user_buffer_size 擷取套接字的使用者資料的大小

lrs_set_send_buffer 指定要在套接字上發送的緩沖區

  環境函數:

  lrs_cleanup 終止Windows套接字 DLL 的使用

  lrs_startup 初始化 Windows 套接字 DLL

  關聯語句函數:

  lrs_save_param 将靜态或接收到的緩沖區(或緩沖區部分)儲存到參數中

  lrs_save_param_ex 将使用者、靜态或接收到的緩沖區(或緩沖區部分)儲存到參數中

  lrs_save_searched_string 在靜态或接收到的緩沖區中搜尋出現的字元串,将出現字元串的緩沖區部分儲存到參數中

  轉換函數:

  lrs_ascii_to_ebcdic 将緩沖區資料從 ASCII 格式轉換成 EBCDIC 格式

  lrs_decimal_to_hex_string 将十進制整數轉換為十六進制字元串

  lrs_ebcdic_to_ascii 将緩沖區資料從 EBCDIC 格式轉換成ASCII 格式

  lrs_hex_string_to_int 将十六進制字元串轉換為整數

  逾時函數:(這一堆函數,是可以對同一個socket生效的)

  lrs_set_accept_timeout 為接受套接字設定逾時

  lrs_set_connect_timeout 為連接配接到套接字設定逾時

  lrs_set_recv_timeout 執行lrs_receive指令後,等待伺服器傳回消息的逾時時間,即伺服器的響應時間。

  lrs_set_recv_timeout2 建立連接配接成功,接收到伺服器傳回的消息後,擷取比對消息的逾時時間。lrs_receive接收到資料後,會和預期的資料長度進行比較,如果長度不比對,它将重新從套接字上讀取資料,直到逾時為止。

  lrs_set_send_timeout 為發送套接字資料設定逾時

  六、實戰講解

  在此隻做簡單的知識普及,便于快速上手編寫socket測試腳本。簡述建立連接配接,收發協定,關閉連接配接的過程。

  初始化

//存放通信傳回封包

char * ActualBuffer="";

//存放傳回封包長度,切記附初值

int numberOfResponse = -1;

//連結是否建立成功,判斷值

int rc = 0;

//傳回封包是否成功,判斷值

int msgOk=-1;

//存放傳回封包

char * position="";

//傳回封包是否成功辨別

char * passMsg="succee";

 伺服器監聽

//--------------建立連接配接-----------------

rc= lrs_create_socket("socket0", "TCP", "LocalHost=0", "RemoteHost=<RemoteHost>", LrsLastArg);

if (rc==0){

//判斷連接配接是否建立成功

lr_output_message("Socket was successfully created ");

}

else{

lr_output_message("An error occurred while creating the socket, Error Code: %d", rc);

  收發協定

lrs_send("socket0", "buf0", LrsLastArg);

//往“socket0”發送"buf0"

lrs_set_receive_option(EndMarker, BinaryStringTerminator, "</html>");

//設定接收協定包選項,注"</html>"以實際定義協定為準,如果不設定次項。執行到lrs_receive的時候,log裡面列印Waiting for writable socket 10

//secs, 0 usecs,都需要等待10秒鐘。是這樣的,因為你在data.ws中定義了recv buffer的長度,例如你定義為100,但是socket上的傳回buffer長度不

//是100,這時候,loadrunner會嘗試再次去讀取,直到讀到長度為100的buffer才算成功。

lrs_receive("socket0", "buf1","Flags=MSG_PEEK ", LrsLastArg);

//将“socket0”中傳回的資料存放到“buf1”中

  參數配置

  可能細心的同學已經發現了,buf0與buf1是從哪裡來的。其實這倆兄弟是在data.ws中被定義的,如下所示:

  ;WSRData 2 1

  send buf0 5120

  "<參數化>"

  recv buf1 1024

  -1

  5120:此數值為socket協定傳輸内容長度,切記嚴格輸入正确長度值。

  "<參數化>":為buf0所傳輸内容。相對于loadrunner的http協定參數用{}來說,socket協定參數化采用<>作為定義符。

  接收參數判斷

  在做了接收之後,我們需要提取“buf1”中的某些關鍵字元作為通信成功辨別。

//擷取套接字上接收到的最後的緩沖區及其大小

lrs_get_last_received_buffer("socket0",&ActualBuffer,&numberOfResponse);

//查詢傳回封包是否成功

position = (char *)strstr(ActualBuffer, passMsg);

// strstr has returned the address. Now calculate * the offset from the beginning of str

msgOk = (int)(position - ActualBuffer + 1);

if(msgOk>0){

lr_end_transaction("核心對私維護", LR_PASS);

lr_output_message("本次交易:%s",ActualBuffer);

lr_end_transaction("核心對私維護", LR_FAIL);

lr_error_message("本次交易:%s",ActualBuffer);

關閉連接配接

//--------------斷開socket--------------

lrs_disable_socket("socket0", DISABLE_SEND_RECV);

//--------------關閉socket--------------

lrs_close_socket("socket0");

  六、總結

  簡要描述了利用Loadrunner編寫socket性能測試腳本的過程,如有錯漏,請予以指正。

注:

strstr(str1,str2) 函數用于判斷字元串str2是否是str1的子串。如果是,則該函數傳回str2在str1中首次出現的位址;否則,傳回NULL。

函數原型:extern char *strstr(char *str1, const char *str2);

文法:

* strstr(str1,str2)

str1: 被查找目标 string expression to search.

str2: 要查找對象 The string expression to find.

傳回值:若str2是str1的子串,則傳回str2在str1的首次出現的位址;如果str2不是str1的子串,則傳回NULL。

例子:

char str[]="1234xyz";

char *str1=strstr(str,"34");

cout << str1 << endl;

顯示的是: 34xyz;顯示比對後全部資料;

本文轉自 知止内明 51CTO部落格,原文連結:http://blog.51cto.com/357712148/1709652,如需轉載請自行聯系原作者

繼續閱讀