本文主要讲述了Socket协议脚本的基础知识和编写方法,让你们可以在短期内快速掌握简单的Socket协议脚本的编写方法。
1.socket协议介绍
Socket协议有万能协议之称,不少系统底层都是用的socket协议,用处十分普遍。
1.1 Socket通信方式说明
与socket通信有两种方式,一种是创建长链接,创建后不停的发送,接收;另外一种是创建短链接,即创建链接发送报文,接收报文关闭链接
1.2 Socket协议发送的buf类型介绍
Send buffer类型分为字符串和xml类型
1.3 Socket协议脚本编写前提:
与项目组沟通,确认是不是socket协议,由项目组提供服务器IP和端口号还有socket协议交易的报文发送及接收报文对,及交易接口文档,了解清楚报文的数据长度,参数化字段,结构,表明什么等,了解清楚后进行socket协议脚本的开发。
1.四、Socket协议脚本函数说明及实例:
1)名称 lrs_create_socket();
建立socket链接,添加IP和端口号,若是建立成功返回值为0,反之则返回为非0数值。(对于长链接,创建socket链接放在vuser_init函数中,短链接放在Action中便可) 实例: lrs_create_socket("socket0","TCP","RemoteHost=180.170.150.230:7700", LrsLastArg);
2)名称 lrs_send();
发送socket请求消息,取缓冲区buf0的报文并发送。
实例: lrs_send("socket0","buf1",LrsLastArg);
3)名称 lrs_receive();
接收socket的响应报文,放置buf1中。
实例:lrs_receive("socket0","buf2",LrsLastArg);
4)名称 lrs_get_last_received_buffer();
获取最后收到的buffer和大小,其中将最后收到的buffer的值赋给RecvBuf变量,将大小赋值给RecvLen。
实例: lrs_get_last_received_buffer("socket0",&recvBuf,&recvLen);
5)名称 lrs_free_buffer();
为防止内存泄露,释放内存空间。
实例: lrs_free_buffer(recvBuf);
6)名称 lrs_close_socket();
关闭Socket链接,(对于长链接,关闭socket链接应放在vuser_end函数中)
实例: lrs_close_socket("socket0");
其余经常使用的Socket函数:
lrs_set_send_buffer("socket0", sSendPkg, iLenOfPkg );//指定要发送的socket信息
lrs_get_buffer_by_name("buf0", sSendPkg, iLenOfPkg);// 获取收到的buffer和大小
lrs_length_send("socket0","buf0",1,"Size=4","Encoding=1",LrsLastArg);
关联函数:
lrs_save_param_ex("socket0","received","",151,7,"ascii","response");//取指定位置字符串保存到变量,以便判断事务是否成功
lrs_save_searched_string();//在指定位置搜索字符串,将出现的字符串报错到参数中
超时函数
lrs_set_connect_timeout();//设置链接超时时间
lrs_set_recv_timeout();//设置服务器响应超时时间
lrs_set_recv_timeout2();//设置接收超时时间,使系统不去检查回收的内容是否一致
二、Socket脚本编写
2.1 简单划分步骤
这种方法是我无心在一片文章中看到的,整体说来,比较简单。就像把大象放进冰箱同样,总共分三步:
第一步:把冰箱门打开
//创建到服务端的链接
rc = lrs_create_socket("socket0", "TCP", "LocalHost=0", "RemoteHost=128.64.64.23:8988", 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_receive("socket0", "buf1", LrsLastArg);//将"socke0"中返回的数据存放到"buf1"中
第三步:把冰箱门带上
//关闭链接
lrs_close_socket("socket0");
2.2 详细划分步骤
◇变量的声明与定义
◇ 建立socket链接
◇ 发送socket请求
◇ 接收socket响应
◇ 从返回Buffer 中抽取结果
◇ 结果判断
◇ 释放内存
◇ 断开链接。
2.3 实例脚本
下面咱们就是用一个实际项目不一样报文格式的脚本进行讲解;
若项目是短链接,且报文不是从文件中读取信息时,vuser_init和vuser_end部分默认便可,主要在Action中开发测试脚本和在data.ws中传输数据到Action的代码中。
Vuser_init.c
#include "lrs.h"
vuser_init()
{
lrs_startup(257);
return 0;
}
Action.c
#include "lrs.h"
Action()
{
int rc,rv;//保存链接成功返回值
char *recvBuf;//保存接收数据的内容
int recvLen;//保存接收数据的大小
/*对于长链接,创建socket链接放在vuser_init函数中,短链接放在Action中便可*/
rc=lrs_create_socket("socket0","TCP","RemoteHost=IP:端口", LrsLastArg);
//判断链接是否建立成功
if(rc==0){
lr_output_message("Socket链接建立成功");
}
else{
lr_error_message("Socket链接建立失败!错误码=%d",rc);
return -1;
}
lr_start_transaction("XXXX_1234_FCX");//事务开始
//发送socket请求消息(数据包内容放在data.ws中)
lrs_send("socket0", "buf0", LrsLastArg); //取缓冲区buf0的报文并发送
rv = lrs_receive("socket0", "buf1", LrsLastArg);//接收响应报文
if(rv==0){
lr_output_message("Socket接收返回消息成功");
}
else{
lr_error_message("Socket接收返回消息失败!错误码=%d",rv);
return -1;
}
//获取最后收到的buffer和大小
lrs_get_last_received_buffer("socket0",&recvBuf,&recvLen);
/*设置检查点,验证返回数据是否成功,这个根据各交易具体状况进行判断,如下示例是经过返回报文的长度大于3即为成功*/
if(recvLen>3){
lr_end_transaction("XXXX_1234_FCX ",PASS);
}
else{
lr_end_transaction("XXXX_1234_FCX ",FAIL);
lr_error_message("XXXX_8550_FCX Fail!出错信息:[%s]", recvBuf);//交易失败时,输出RecvBuf返回信息,用于排查出错缘由
}
lrs_free_buffer(recvBuf); //释放recvBuf内存空间,不然会引发内存泄露
/*关闭Socket链接,对于长链接,关闭socket链接应放在vuser_end函数中*/
lrs_close_socket("socket0");
return 0;
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(JobService.class);
for (String beanname:context.getBeanDefinitionNames())
{
System.out.println("--------"+beanname);
}
System.out.println("context.getBean(JobService.class) = " + context.getBean(JobService.class));
复制代码
这点代码很简单 初始化bean,而后再来拿bean,咱们点进AnnotationConfigApplicationContext来看
复制代码
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses)
{
this();
register(annotatedClasses);
refresh();
}
复制代码
进⼊以后 会调用 this()默认无参构造方法
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new www.tianjiuyule178.com ClassPathBeanDefinitionScanner(this);
}
调⽤这个⽆参构造⽅法的同时 他会调用⽗类的构造方法,在调用父类构造⽅方法时 他new了一个对象
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
也就是 DefaultListableBeanFactory,固然 这个就是所谓咱们日常所说的 bean工厂,其父类就是 BeanFactory,BeanFactory有不少子类,DefaultListableBeanFactory就是其中一个⼦类。 那么 bean的⽣命周期是围绕那个⽅法呢,就是refresh()⽅法。也就是bean的整个生命周期是围绕refresh() 来进行的
在refresh()咱们能够看到
复制代码
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor)www.dayuzaixianyL.cn {
// 准备好刷新上下文.
prepareRefresh();
// 返回一个Factory 为何须要返回一个工厂 由于要对工厂进行初始化
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备bean工厂,以便在此上下文中使用。
prepareBeanFactory(beanFactory);
try {
// 容许在上下文子类中对bean工厂进行后处理。 在spring5 并未对此接口进行实现
postProcessBeanFactory(beanFactory);
// 在spring的环境中去执行已经被注册的 Factory processors
//设置执行自定义的postProcessBeanFactory和spring内部本身定义的
invokeBeanFactoryPostProcessors(beanFactory);
// 注册postProcessor
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源。
initMessageSource();
// 初始化此上下文的事件多播程序。
initApplicationEventMulticaster();
// 在特定上下文子类中初始化其余特殊bean。
onRefresh();
//检查侦听器bean并注册它们。
registerListeners();
// 实例化全部剩余的(非懒加载)单例。
//new 单例对象
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans(www.hnxinhe.cn);
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
复制代码
那么这里面最重要就是finishBeanFactoryInitialization(beanFactory);这个方法就是描述 spring的一个bean如何初始化
复制代码
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver(www.yunyouuyL.com)) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment(www.chenghgongs.com).resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// 实例化全部单例对象
beanFactory.preInstantiateSingletons();
}
复制代码
能够看到前面是一些判断 最重要的就是最后一个方法 beanFactory.preInstantiateSingletons();咱们看下preInstantiateSingletons()方法,它是ConfigurableListableBeanFactory这个接口的一个方法 咱们直接来看这个接口的实现 是由DefaultListableBeanFactory这个类 来实现
复制代码
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Pre-instantiating singletons in www.baihuiyulegw.com " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
//全部bean的名字
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<www.tianscpt.com>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
data.ws
1)XML报文格式
;WSRData 2 1
send buf0 360
"<?xmlversion=\"1.0\"encoding=\"GBK\"?>"
"<TRANINFO>"
"<HEAD>"
"<TransCode>S001</TransCode>"
"<TransDate>20170613</TransDate>"
"<TransTime>144206</TransTime>"
"<TransNo>21219603</TransNo>"
"<Operator>999088</Operator>"
"<TransInst>70090</TransInst>"
"</HEAD>"
"<MSG>"
"<CustomerID><userID></CustomerID>"//客户编号
"<Type>3</Type>"//查询类型
"<BusinessType>01</BusinessType>"//业务类型
"</MSG>"
"</TRANINFO>"
recv buf1 300
-1
2)16进制报文格式
;WSRData 2 1
send buf0 32
"\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
" "
"\x00\x00\x00\x00"
"PID <tran>"
recv buf1 197
"\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x1e\x00\x00\x00\x00"
"STW -1"
"\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x1e\x00\x00\x00\x00"
"STT "
"\x1f"
-1
其中buf0表明发送的报文的名称,后跟的数字代码发送报文长度,其下放置发送报文;buf1表明接收报文的名称,后跟数字表明接收报文长度,其下放置接收报文。
注意:该协议脚本参数化格式为:<参数名>spring