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

172 阅读3分钟
  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;

}

运行结果如下:

代码链接:download.csdn.net/download/hh…