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

一、概述

  Loadrunner擁有極爲豐富的工具箱,供予我們製造出各種奇妙魔法的能力。其中就有此次要討論的socket套接字操作。

  二、socket概述

  socket是操作系統中I/O系統的網絡延伸部分,它擴展了操作系統的基本I/O到網絡通信,使進程和機器之間的通信成爲可能。如果想完全地理解socket在Loadrunner中如何工作的,熟悉一些關於它的歷史會很有幫助。

  當前常用的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)來訪問文件。文件描述符是非負整數。打開現存文件或新建文件時,內核會返回一個文件描述符。讀寫文件也需要使用文件描述符來指定待讀寫的文件。

  文件描述符在形式上是一個非負整數。實際上,它是一個索引值,指向內核爲每一個進程所維護的該進程打開文件的記錄表。當程序打開一個現有文件或者創建一個新文件時,內核向進程返回一個文件描述符。在程序設計中,一些涉及底層的程序編寫往往會圍繞着文件描述符展開。但是文件描述符這一概念往往只適用於UNIX、Linux這樣的操作系統。

  三、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相關函數淺析

  Loadrunner對於腳本函數有一份幫助文檔。利用好此文檔,其實對於性能測試所需腳本就已足以。

  當我們打開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_close_socket 關閉打開的套接字

lrs_create_socket 初始化套接字

lrs_disable_socket 禁用套接字操作

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);

}

else{

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;顯示匹配後全部數據;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章