利用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性能測試腳本的過程,如有錯漏,請予以指正。
posted on 2014-08-05 09:53 順其自然EVO 閱讀(17370) 評論(0) 編輯 收藏 所屬分類: 測試學習專欄 、loadrunner