品味性能之道<九>:利用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性能测试脚本的过程,如有错漏,请予以指正。

  • 引用文献

志良的技术博客http://www.cnblogs.com/tianzhiliang/archive/2012/03/20/2407940.html

百度百科http://baike.baidu.com/view/13870.htm?fr=aladdin

http://baike.baidu.com/view/1303430.htm?fr=aladdin

胡杨的学习笔记http://hi.baidu.com/yangliu9420/archive/tag/python

CocoaChina 开发讨论区http://www.cocoachina.com/bbs/simple/?t124371.html

  • 鸣谢

QQ好友:培昊、果冻(wd)

品味性能之道<九>:利用Loadrunner编写socket性能测试脚本简述

时间: 2024-12-15 00:25:18

品味性能之道<九>:利用Loadrunner编写socket性能测试脚本简述的相关文章

LoadRunner编写Socket协议脚本方法

本文主要介绍使用LoadRunner手工编写Windows Socket协议测试脚本的方法. 通过LoadRunner编写Windows Socket协议测试脚本,总体说来,比较简单.就像把大象放进冰箱一样,总共分三步: 第一步:把冰箱门打开 //建立到服务端的连接 rc =    lrs_create_socket("socket0", "TCP", "LocalHost=0", "RemoteHost=128.64.64.23:89

LR杂记-用LoadRunner编写socket应用的测试脚本

LoadRunner提供了很好的对socket应用的支持,用户可以通过录制方法完全获得客户端发送和接收的数据,然后在录制的基础上对相应的数据进行参数化和关联等处理. 但在有些情况下(例如,客户端程序没有windows上的版本),我们就很难通过录制达成生成脚本的目标了.但如果我们能够完全知晓服务端和客户端的交互过程,完全手工编写一个测试脚本也并不是一件特别困难的事情. 在本文中,我们以一个实际的例子说明如何根据服务端和客户端交互的过程,用LoadRunner自行编写相应的脚本. 以下是服务端工作线

loadrunner 编写socket脚本实例(附服务端实现)

一.socket背景知识 这个咱就不废话了,网上一搜一大堆 二.本实例实现的功能 服务端接收客户端发送的字符串,并返回"5678succ"共8个字符 三.服务端实现(java代码) ①MySocketServer.java package serverSocketMultiThreadVer; import java.io.IOException;import java.net.InetAddress;import java.net.ServerSocket;import java.n

利用LoadRunner判断HTTP服务器的返回状态

利用LoadRunner判断HTTP服务器的返回状态第一种方法:是利用LR的内置函数web_get_int_property.举例:#include "web_api.h"Action(){int HttpRetCode;web_url("网易",       "URL=http://www.163.com",       "TargetFrame=_TOP",       LAST);HttpRetCode = web_ge

利用多线程编写 生产者-消费者 关系

package ace; import java.util.ArrayList; import java.util.Timer; import java.util.TimerTask; /** * 利用多线程编写 生产者-消费者 关系 */ public class ProductionAndConsumption { private static ArrayList<String> products = new ArrayList<String>(); // 产品 private

看我如何利用Shell编写vsftpd管理软件

今天弄服务器的时候无意间用到此脚本,觉得当时写的虽然不咋样,但还是有点借鉴意义,就拿出来给大家看看.希望大家喜欢 先看看演示视频 看我如何利用Shell编写vsftpd管理软件 高清版下载: 百度云下载 OK然后我们来看看脚本的实现过程,时间有点久了当时的想法可能现在有点想不起来了,解释的不对的地方望见谅 脚本分为7个部分,这里我只做简单的解释 第一部分 脚本开始就利用awk提取日志中的用户名字段保存到tmp目录下的ftplog-userlist.txt文件中,方便后面查询 然后开始信息的展示,

如何利用CSS3编写一个满屏的布局

如何利用CSS3编写一个满屏的布局 css3的出现能帮助我们更加轻松的实现各种想要的效果,例如写一个刚好满屏的布局,我们就可以利用CSS3的弹性盒模型来实现. 先来贴出html布局代码: 1 <%- include header %> 2 <div class="wrapper"> 3 <div id="appswall"> 4 <div class="adsapp-title"><butto

Dialog(九)——利用WindowManager在屏幕任意位置添加Dialog

MainActivity如下: package cn.testalertdialog; import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import andro

利用MFC编写计算器

端午节这两天没什么事,就用MFC写了一个简单的计算器,界面做的也比较简单,如下图1,可以进行简单的加.减.乘和除功能,小数点显示这块做的不是很好,比如输入1.2,不会一个个的显示,而是先显示"1",后同时显示".2",还有就是遇到0.00时,显示的也不够人性化,哎,就这样吧... 图1 1.建立工程:New -> Projects,选择Win32 MFC AppWizard(exe),并输入工程(counter)名字及设置好路径,点击OK,选择"Di