一、概述
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);
}
//--------------创建连接-----------------
lr_start_transaction("事务");
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”中
在做了接收之后,我们需要提取“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");
可能细心的同学已经发现了,buf0与buf1是从哪里来的。其实这俩兄弟是在data.ws中被定义的,如下所示:
;WSRData 2 1
send buf0 5120
"<参数化>"
recv buf1 1024
-1
5120:此数值为socket协议传输内容长度,切记严格输入正确长度值。
"<参数化>":为buf0所传输内容。相对于loadrunner的http协议参数用{}来说,socket协议参数化采用<>作为定义符。
六、总结
简要描述了利用Loadrunner编写socket性能测试脚本的过程,如有错漏,请予以指正。
- LoadRunner编写socket性能测试脚本
利用LoadRunner编写socket性能测试脚本 一.概述 Loadrunner拥有极为丰富的工具箱,供予我们制造出各种奇妙魔法的能力.其中就有此次要讨论的socket套接字操作. 二.socke ...
- 品味性能之道<八>:Loadrunner关联技巧与字符处理
一.概述 Loadrunner作为HP出品的性能测试工具,拥有太多奇妙魔法甜点供予性能测试人员享用,其中吃起来比较有嚼劲的那就是关联了.当然在关联之后我们还需要一些简单的字符处理,用以生成 ...
- LoadRunner编写Socket协议脚本方法
本文主要介绍使用LoadRunner手工编写Windows Socket协议测试脚本的方法. 通过LoadRunner编写Windows Socket协议测试脚本,总体说来,比较简单.就像把大象放进冰 ...
- 品味性能之道<十一>:JAVA中switch和if性能比较
通常而言大家普遍的认知里switch case的效率高于if else.根据我的理解而言switch的查找类似于二叉树,if则是线性查找.按照此逻辑推理对于对比条件数目大于3时switch更优,并且对 ...
- 品味性能之道<十>:Oracle Hint
Hint 是Oracle 提供的一种SQL语法,它允许用户在SQL语句中插入相关的语法,从而影响SQL的执行方式. 因为Hint的特殊作用,所以对于开发人员不应该在代码中使用它,Hint 更像是Ora ...
- 品味性能之道<七>:索引基础
一.索引概述 索引(index),它是数据库必不可少的一部分.它其实很简单呐!很好理解. 索引好比如一本书的目录,一张地图,一个写字楼里挂在大堂墙上的公司名录,一个地铁站的出口指示 ...
- 品味性能之道<六>:图形化SQL分析工具
在上一章里,重点分享了命令行SQL分析工具的使用方法.在本章将重点分享PL/SQL的SQL分析工具. 一.如何打开PL/SQL执行计划 开启PL/SQL这工具,推荐如下方法: 点击 ...
- 品味性能之道<五>:SQL分析工具
一.SQL语句到底是怎么执行的? 想了解SQL语句到底是怎么执行的,那就需要进行SQL语句执行计划分析. 那什么是SQL语句执行计划呢? 就是Oracle服务器执行SQL语句的过程.例如确定是否使用索 ...
- 品味性能之道<三>:方法论
自顶向下的性能优化方法论 系统优化是包括系统设计.开发.产品上线.平台优化的全过程,不同阶段的优化工作对全系统所带来的效益是不同的.理想的性能优化论应该采用自顶向下的优化方法,即在项目设计.开发和上线 ...
随机推荐
- create-react-app之proxy
[create-react-app之proxy] create-react-app可以用于一键创建web_client环境,默认使用webpack-dev-server.但在开发过程中,往往需要cli ...
- NPM安装依赖速度慢问题
[NPM安装依赖速度慢问题] npm config set registry http://registry.npm.taobao.org 参考:http://blog.csdn.net/rongbo ...
- 获取cookie
1.cookie是存储在用户本地终端的数据,实际上是一小段的文本信息 2.cookie的作用 帮助web站点保存有关的访问者的信息,方便用户的访问,如记住用户名和密码,实现自动登录功能案例:查看访问我 ...
- WPF双向绑定
需求: 思想批量保存数据. 思路: 看了一下MVVM.发现只需要实现前台和后台数据的同步即可.也就是前台的文本框内容变化时后台的对象的属性也要变化就可以了. 参考: http://www.cnblog ...
- Numpy:索引与切片
numpy基本的索引和切片 import numpy as np arr = np.array([1,2,3,555,666,888,10]) arr array([ 1, 2, 3, 555, 66 ...
- python计算两个数的百分比
a和b是整数,计算a/b的百分比 a=3 b=7 a=float(a) b=float(b) 保留百分比后2位小数 print "%.2f%%" % (a/b*100) '42. ...
- ORM之查询
一.对象查询 1.正向查询 ret1=models.Book.objects.first() print(ret1.title) print(ret1.price) print(ret1.publis ...
- 生成二维码的JAVA
不多说,上代码 package tcc; import java.awt.Color;import java.awt.Graphics2D;import java.awt.image.Buffered ...
- Apache+PHP+MySQL环境搭建
准备安装包:Apache: apache_2.2.11-win32.msi (http://pan.baidu.com/s/1nvdiNcH)PHP: php-5.2.5-Win32.zip (htt ...
- JavaScript各种继承方式(四):原型式继承(prototypal inheritance)
一 原理 利用工具函数,通过原型对象直接得到父类的实例,并当作子类对实例使用. function inherit(obj){ // 在闭包中创建子类,对外隐藏子类 function Temp(){ } ...