一、概述
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协议问题归纳(6)
首先让我们先看一下loadrunner- winsock 函数 一览表: lrs_accept_connection 接受侦听套接字连接 lrs_close_socket 关闭打开的套接字 ...
- loadrunner socket协议问题归纳(3)
摘要:通过实例讲解loadrunner中的socket协议性能测试的一种测试方法,如何不依赖loadrunner既定规则,自行控制收发数据包 关键词:Loadrunner,socket,自行控制,收发 ...
- loadrunner socket协议问题归纳(1)
前段时间测了loadrunner直接发送报文到socket上的性能测试.在此,稍微回顾整理下. 与socket通讯,有两种方式,一种是建立长连接,建立后,不停的发送,接收.另外一种是建立短连接,建立连 ...
- loadrunner socket协议问题归纳(2)
编写步骤 1.建立与服务端的连接 rc=lrs_create_socket(“socket0”,”TCP”,”LocalHost=0”,”RemoteHost=127.0.0.1:8808”,LrsL ...
- loadrunner socket协议问题归纳(5)
获取服务器的返回值,可以用web_reg_save_param函数,该参数最好放到: 语法: int web_reg_save_param(const char *ParamName, <lis ...
- loadrunner socket协议问题归纳(4)---buffer接收变长和定长的数据
测试场景:聊天系统 用户登录后,要先向服务器发送用户名,然后可以发送聊天信息,同时也可以接受聊天信息. 如果接受的字符为定长时,可以设定接受长度.recv buf2 66 #include " ...
- Loadrunner socket协议lrs_receive函数接收到返回数据包 仍然等待服务器返回--解决
前段时间在使用loadrunner socket协议发送数据包到到服务器,使用lrs_receive接收服务器应答数据包,已经接收到数据包,但LR仍然在等待服务器端返回,而且日志打印显示每次接收返回都 ...
- LoadRunner编写Socket协议脚本方法
本文主要介绍使用LoadRunner手工编写Windows Socket协议测试脚本的方法. 通过LoadRunner编写Windows Socket协议测试脚本,总体说来,比较简单.就像把大象放进冰 ...
- Loadrunner 中socket协议RecvBuffer接收到数据长度为空
socket通讯,有两种方式,一种是建立长连接(TCP),建立后,不停的发送,接收.另外一种是建立短连接(UDP),建立连接,发送报文,接收响应,关闭连接.两种方式 server的开销不同. 今天出现 ...
随机推荐
- jQuery添加标签实例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- vue组件中,iview的modal组件爬坑--modal的显示与否应该是使用v-show
这是我第一次写博客,主要是记录下自己解决问题的过程和知识的总结,如有不对的地方欢迎指出来! 需求:点击btn,弹出modal显示图表(以折现图为例) 这应该是很基本的需求也是很容易实现的,代码和效果如 ...
- 浅谈 Virtual DOM 的那些事
背景 我们都知道频繁的dom给我们带来的代价是昂贵的,例如我们有时候需要去更新Table 的部分数据,必须去重新重绘表格,这代价实在是太大了,相比于频繁的手动去操作dom而带来性能问题,vdom很好的 ...
- C++笔记015:C++对C的扩展——三目运算符功能增强
原创笔记,转载请注明出处! 点击[关注],关注也是一种美德~ 三目运算符在C编译器中的表现: int main() { int a=10; int b=20; //三目运算符是一个表达式,表达式不能做 ...
- 偏前端 - div+mui+vue.js 制作问卷调查单页 ——题目答案由后台随机给出10道
封装的ajax获取数据.代码可能有些是多余的,没做处理!!点击提交后有弹框,在这里我没有贴出来.第一次写博客,这些也是别人教我的,经理解后,贴出来于大家分享 ——html—— <script t ...
- float(浮动)的属性和使用方法
1float浮动的属性值 left:向左浮动 right:向右浮动 2.当父元素未浮动,子元素浮动时,就会造成浮动塌陷 实例: 父元素: #mainDiv{ border: 5px solid red ...
- Go语言的包管理
1 概述 Go 语言的源码复用建立在包(package)基础之上.包通过 package, import, GOPATH 操作完成. 2 main包 Go 语言的入口 main() 函数所在的包(pa ...
- 动手打造轻量web服务器(二)路由
tomcat启动慢?自己动手打造轻量web服务器(一) 上篇讲了怎么做一个最简单的web服务器,这篇就是在上篇加上URL路由功能(什么是路由?) 首先,根据http获得请求行 val scanner ...
- 20155229 2016-2017-2 《Java程序设计》第二周学习总结
20155229 2016-2017-2 <Java程序设计>第二周学习总结 教材学习内容总结 布尔:boolean类型可表示true和false %符号被用来作为控制符号前置,所以规定用 ...
- day4 边缘检测Canny
1.canny边缘检测 # coding=utf-8 import cv2 import numpy as np filename = 'woman.JPEG' #读入图像,以灰度格式 img = c ...