本文共 4263 字,大约阅读时间需要 14 分钟。
1 背景“驱动+桩”是一种比较成熟的服务器端模块测试模式,易于实施自动化。
Receiver应用于桩构建的场景,提高构建服务器端测试桩的效率,在大多数应用场景下用户可以通过配置xml文件实习桩功能,支持功能和性能测试使用 Receiver只支持linux环境使用2 名词解释A模式: 普通xml解析模式 B模式: 逻辑xml解析模式 C模式: so加载模式3 功能 ※能够模拟提供二进制socket接口的服务器程序 ※能够支持功能与性能的要求 ※提供三种使用模式: (1) 普通xml解析模式(模拟单个接口,指定接口格式及回报数据) (2) 逻辑xml解析模式(模拟多个接口,除指定接口格式及回报数据外,定制部分逻辑) (3) so加载模式(特殊场景使用,用户可以自己实现包处理函数) ※ 提供各类辅助函数, 帮助更快速的开发桩程序4 使用说明4.1 普通xml模式假设一个服务器模块提供的某个socket接口请求格式为header+req1,回包格式为header+resp1,struct描述如下: struct header{ int cmd; char provider[200]; int len; }; struct req1{ int id; }; Struct item{ Int a; Int b; }; struct resp1{ int result; char name[50]; int count; struct item items[]; }; 那么我们需要先构造三个xml描述 ※header1.xml <packet type="struct" repeat="1" value=" header" endian="0"> <cmd type="int32_t" value="" repeat="1"/> <provider type="char" value="" repeat="200"/> <len type=”int32_t” value=” #flowlen()” repeat="1"> </packet> ※req1.xml <packet type="struct" repeat="1" value=" req1" endian="0"> <id type="int32_t" value="" repeat="1"/> </packet> ※ resp1.xml <packet type="struct" repeat="1" value=" resp1" endian="0"> <result type="int32_t" value="$TEMPRESULT" repeat="1"/> <name type="char" value="hello world" repeat="50"/> <count type="int32_t" value="5" repeat="1"/> <items type="struct" repeat="@count" value=" "> <a type="int32_t" value="1" repeat="1"/> <b type="int32_t" value="2" repeat="1"/> </items> </packet>注:endian用来描述字节序,0为主机序(默认)
Repeat用于指定该数据段重复数字,用于数组定义,也可以用在struct的描述上 Type为该字段类型,工具内置类型见附录 #flowlen()为内置函数,指定此处自动计算,根据后面所有结构体的长度计算,其他关键字见附录 $TEMPRESULT表示从环境变量TEMPRESULT中读取数据 @count 表示该字段值由<count type="int32_t" value="5" repeat="1"/>值反填,也就是5 回包值可以指定固定值、从环境变量中读取或者利用random内置函数随机生成 运行receiver:./receiver –p 3306 –r ./header.xml –r req1.xml –s header.xml –s resp1.xml -l 1 -u 0 -n -1 即可模拟这个服务器的接口 那么当receiver收到一个header+req1的请求,它会回一个header+resp1的应答(result为对应系统变量实际值,name为hello world),-l 1表示长连接, -u 0 表示tcp请求, -n -1 表示receiver不会退出,一直处理请求4.2 逻辑xml模式上个例子给出了模拟一个服务器程序单一接口的使用方法,逻辑xml主要用于模拟一个程序多个接口的场景。
假设说某模块提供的接口格式如下: header1+header2+reqX 回包格式为: header1+header2+respX (X为未知数,具体请求与回应的结构体由header2中的cmd域来定义,例如如果cmd取值为5,则请求为header1+header2+req5,回应为header1+header2+resp5) 我们想启动一个桩实例来模拟这些接口,那么可以使用逻辑xml模式,逻辑xmll的使用方法如下: 首先构造逻辑xml: [gaowei@db-testing-cs33.db01.baidu.com receiver]$ cat xml/config.xml <config> <req_header path="header1.xml" /><!—请求包头1--> <req_header path="header2.xml " key="cmd" /><!—请求包头2,这个结构体中的cmd决定如何回包--> <resp_body key="1" respkey="5" path="resp1.xml " /><!—如果cmd为1,则用resp1回包 --> <resp_body key="2" respkey="6" path="resp2.xml" /><!—如果cmd为2,则用resp2回包 --> </config> 运行receiver:./receiver –p 3306 –b config.xml -l 1 -u 0 -n -1 –t 5即可模拟这个服务器的多个接口4.3 so模式如果以上两种方式不能满足用户需求,用户可以继承receiver提供的plugin基类,实现自己的包处理函数 class IPlugin { public: IPlugin( const std::string& name) ; virtual ~IPlugin(); virtual const std::string& GetPluginName(); virtual void Process( void *); protected: std::string m_strPluginName; };Receiver使用了Epool和线程池模型,当有socket可读,会立刻回调用户的Process( void *)函数,传给用户socket句柄,用户可自行执行收包及处理函数
一个简单示例如下: testplugin.h: #include "plugin.h" class TestPlugin: public IPlugin{ public: TestPlugin():IPlugin("testplugin"){ printf("create TestPlugin\n"); } void Process( void *); };testplugin.cpp:
#include "testplugin.h" #include "mysocket.h" #include <iostream> using namespace std;extern "C"
TestPlugin* create_testplugin() { return new TestPlugin(); } void TestPlugin::Process(void * p){ int sock = (int)p; cout << " handle epool event , socket= " << sock << endl; SocketLayer::close_delepoll(sock); }5 工具参数receiver三种模式: xml模式(A),逻辑xml模式(B),so模式(C),参数含义如下: -r 指定接收的结构体描述,A模式使用 -s 指定发送的普通结构体描述,A模式使用 -m 指定发送的mcpack1结构体描述,A模式使用 -x 指定发送的mcpack2结构体描述,A模式使用 -S 指定延迟发送时间,A、B模式使用 -n 指定响应次数(-1 表示不退出),A、B模式使用 -l 指定处理请求后是否断连接,A、B模式使用 -u 指定是否为udp,A、B模式使用 -b 指定一个逻辑xml,B模式使用 -d 指定自定义so路径,C模式使用 -a 指定自定义so名称,C模式使用 -t 指定线程数,A、B、C模式使用 -p 指定端口号,A、B、C模式使用6 附录6.1 关键字列表 #randuint(a,b):返回从a到b之间的一个随机数
#timenow():返回当前时间的秒数 #md5(16,str):根据str生成md5 #fromto(a,b):返回[a,b]的整数,随运行次数递增 #randin(a,b,c,d):在abcd中随机抽一个数 flowlen():计算后续部分的长度6.2 内置类型 int8_t uint8_t
int16_t uint16_t int32_t uint32_t int64_t uint64_t int time_t long short char(baiduqa,邮箱:)