利用函数指针实现C的回调函数,实现调用者和底层驱动的解耦 第二种方式

举报
AI浩 发表于 2021/12/22 23:46:35 2021/12/22
【摘要】 新建空项目,命名为RF_Drive,这个作为底层的驱动。 添加MyDrive.c文件,向文件中添加代码,模拟驱动一些函数,代码如下:   思路: EncData和DecData实现信息的加密和解密,由于不同厂家的设备,加密和解密的方式不同,所以不能在底层驱动中实现,需要不同的厂家在自己的函数库中实现。厂家和驱动约定好相...
  1. 新建空项目,命名为RF_Drive,这个作为底层的驱动。

  1. 添加MyDrive.c文件,向文件中添加代码,模拟驱动一些函数,代码如下:

 

思路:

EncData和DecData实现信息的加密和解密,由于不同厂家的设备,加密和解密的方式不同,所以不能在底层驱动中实现,需要不同的厂家在自己的函数库中实现。厂家和驱动约定好相同的接口,将函数通过指针通过调用socketclient_SetEncDataCallback函数,提前将函数存放到Sck_Handle里面。


      #define  _CRT_SECURE_NO_WARNINGS
      #include <stdlib.h>
      #include <string.h>
      #include <stdio.h>
      #include "MyDrive.h"
      typedef struct _Sck_Handle
      {
          char    version[16];
          char    ip[16];
          int     port;
          unsigned char *p;
          int         len;
          char        *p2;
          EncData  Hw_EncData;
      }Sck_Handle;
      int  socketclient_SetEncDataCallback(void *handle, EncData Hw_EncData)
      {
          int ret = 0;
          Sck_Handle  *tmpHandle = NULL;
          if (handle == NULL || Hw_EncData == NULL)
          {
              ret = -1;
              printf("func socketclient_SetEncDataCallback() err :%d  check handle == NULL err \n", ret);
              return ret;
          }
          tmpHandle = (Sck_Handle *)handle;
          tmpHandle->Hw_EncData = Hw_EncData;//提前把回调函数的入口地址 缓存到 句柄handle 上下文中
          return 0;
      }
      int socketclient_init(void **handle)
      {
          int         ret = 0;
          Sck_Handle  *tmpHandle = NULL;
          if (handle == NULL)
          {
              ret = -1;
              printf("func socketclient_init() err :%d  check handle == NULL err \n", ret);
              return ret;
          }
          tmpHandle = (Sck_Handle *)malloc(sizeof(Sck_Handle));
          if (tmpHandle == NULL)
          {
              ret = -2;
              printf("func socketclient_init() err :%d  malloc err \n", ret);
              return ret;
          }
          memset(tmpHandle, 0, sizeof(Sck_Handle));
          strcpy(tmpHandle->version, "1.0.0.1");
          strcpy(tmpHandle->ip, "192.168.12.12");
          tmpHandle->port = 8081;
          //间接赋值
          *handle = tmpHandle;
          return ret;
      }
      int socketclient_send(void *handle, unsigned char *buf, int buflen)
      {
          int         ret = 0;
          Sck_Handle  *tmpHandle = NULL;
          if (handle == NULL || buf == NULL || buflen <= 0)
          {
              ret = -2;
              printf("func socketclient_send() err :%d  (handle == NULL ||  buf==NULL || buflen <=0 ) \n", ret);
              return ret;
          }
          tmpHandle = (Sck_Handle *)handle;
          if (tmpHandle->Hw_EncData != NULL) //如果设置了加密函数 则发送报文之前 先对数据进行加密
          {
              unsigned char crypdata[4096];
              int cryptdatalen = 4096;
              ret = tmpHandle->Hw_EncData(buf, buflen, crypdata, &cryptdatalen);
              if (ret != 0)
              {
                  printf("func Hw_EncData() err :%d  \n", ret);
                  return ret;
              }
              tmpHandle->len = cryptdatalen;
              tmpHandle->p = (unsigned char *)malloc(cryptdatalen);
              if (tmpHandle->p == NULL)
              {
                  ret = -1;
                  printf("func Hw_EncData() err :%d malloc err \n", ret);
                  return ret;
              }
              memcpy(tmpHandle->p, crypdata, cryptdatalen); //缓存密文
          }
          else
          {
              tmpHandle->len = buflen;
              tmpHandle->p = (unsigned char *)malloc(buflen);
              if (tmpHandle->p == NULL)
              {
                  ret = -2;
                  printf("func socketclient_send() err :%d  malloc len:%d \n", ret, buflen);
                  return ret;
              }
              memcpy(tmpHandle->p, buf, buflen); //数据的缓存到内存
          }
          return ret;
      }
      int socketclient_recv(void *handle, unsigned char *buf, int *buflen)
      {
          int         ret = 0;
          Sck_Handle  *tmpHandle = NULL;
          if (handle == NULL || buf == NULL || buflen == NULL)
          {
              ret = -2;
              printf("func socketclient_recv() err :%d  (handle == NULL ||  buf==NULL || buflen==NULL ) \n", ret);
              return ret;
          }
          tmpHandle = (Sck_Handle *)handle;
          memcpy(buf, tmpHandle->p, tmpHandle->len);
          *buflen = tmpHandle->len; //间接赋值  告诉调用者 收到的数据的长度
          return ret;
      }
      int socketclient_destory(void *handle)
      {
          int         ret = 0;
          Sck_Handle  *tmpHandle = NULL;
          if (handle == NULL)
          {
              return -1;
          }
          tmpHandle = (Sck_Handle *)handle;
          if (tmpHandle->p != NULL)
          {
              free(tmpHandle->p); //释放结构体 成员域的 指针所指向的内存空间
          }
          free(tmpHandle); //释放结构体内存
          return 0;
      }
  
 
  1. 添加MyDrive.h文件。

      #ifndef _INC_MYDRIVE_H__
      #define _INC_MYDRIVE_H__
      #define Import_SSS
      #ifdef Import_SSS
      #define API _declspec(dllexport)
      #else
      #define API _declspec(dllimport)
      #endif
      #ifdef  __cplusplus
      extern "C" {
      #endif
          typedef int(*EncData)(unsigned char *in, int inlen, unsigned char *out, int *outlen);
          typedef int(*DecData)(unsigned char *in, int inlen, unsigned char *out, int *outlen);
          API
              int socketclient_init(void **handle);
          API
              int socketclient_send(void *handle, unsigned char *buf, int buflen);
          API
              int socketclient_SetEncDataCallback(void *handle, EncData Hw_EncData);
          API
              int socketclient_recv(void *handle, unsigned char *buf, int *buflen);
          API
              int socketclient_destory(void *handle);
      #ifdef  __cplusplus
       }
      #endif
      #endif
  
 

 

完成后,右键项目,将配置类型改为dll动态链接库。

  1. 新建TestDrive工程,测试底层dll。将生成的RF_Drive.dll、RF_Drive.lib和MyDrive.h文件放到工程目录下面。

  1. 将RF_Drive链接到TestDrive。选择输入,然后选择附加依赖项,将RF_Drive.lib添加进去,然后点击确定。

  1. 将MyDrive.h包含到项目,然后新建Test.c文件,在Test.c中写入测试代码。代码如下:

 

思路:

在调用者实现加密算法Hw_EncData,不同的调用者,实现加密算法的方式不同,需要调用者自己实现,然后调用socketclient_SetEncDataCallback函数将Hw_EncData存储到handle里面。


      #define  _CRT_SECURE_NO_WARNINGS
      #include <stdlib.h>
      #include <string.h>
      #include <stdio.h>
      #include "MyDrive.h"
      int Hw_EncData(unsigned char *in, int inlen, unsigned char *out, int *outlen)
      {
          printf("func Hw_EncData begin....\n ");
          strcpy((char *)out, "123456789");
          *outlen = 9;
          printf("func Hw_EncData end....\n ");
          return 0;
      }
      //  //设置 加密函数入口地址  回调函数的入口地址
      //ret = socketclient_SetEncCallback(&handle, Hw_EncData);
      //把加密函数的入口地址 提前 塞入到动态库中
      //
      void main()
      {
          unsigned char buf[1024];
          int buflen;
          unsigned char out[1024];
          int outlen;
          void *handle = NULL;
          int ret = 0;
          strcpy((char *)buf, "aaaaaaaaaffffffffdddddddd");
          buflen = 9;
          //客户端初始化 获取handle上下
          ret = socketclient_init(&handle /*out*/);
          if (ret != 0)
          {
              printf("func socketclient_init() err:%d \n ", ret);
              goto End;
          }
          //
          ret = socketclient_SetEncDataCallback(handle, Hw_EncData);
          if (ret != 0)
          {
              printf("func socketclient_SetEncDataCallback() err:%d \n ", ret);
              goto End;
          }
          //客户端发报文
          ret = socketclient_send(handle /*in*/, buf /*in*/, buflen /*in*/);
          if (ret != 0)
          {
              printf("func socketclient_send() err:%d \n ", ret);
              goto End;
          }
          //客户端收报文
          ret = socketclient_recv(handle /*in*/, out /*in*/, &outlen/*in out*/);
          if (ret != 0)
          {
              printf("func socketclient_recv() err:%d \n ", ret);
              goto End;
          }
      End:
          //客户端释放资源
          ret = socketclient_destory(handle/*in*/);
          printf("hello...\n");
          system("pause");
          printf("hello...\n");
          system("pause");
          return;
      }
  
 

运行结果如下:

代码链接:https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/12898350

文章来源: wanghao.blog.csdn.net,作者:AI浩,版权归原作者所有,如需转载,请联系作者。

原文链接:wanghao.blog.csdn.net/article/details/108871906

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。