socket协议介绍

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

  本文主要讲述了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.4、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();//设置接收超时时间,使系统不去检查回收的内容是否一致
  
  2、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 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)
  
  ((SmartFactoryBean) 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
  
  ""
  
  ""
  
  ""
  
  "S001"
  
  "20170613"
  
  "144206"
  
  "21219603"
  
  "999088"
  
  "70090"
  
  ""
  
  ""
  
  ""//客户编号
  
  "3"//查询类型
  
  "01"//业务类型
  
  "
"
  
  "
"
  
  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 "
  
  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代表接收报文的名称,后跟数字代表接收报文长度,其下放置接收报文。
  
  注意:该协议脚本参数化格式为:<参数名>

转载于:https://my.oschina.net/u/3386278/blog/3047626

你可能感兴趣的:(socket协议介绍)