c语言异步回调函数的使用

回调函数的实现

实现的功能:

        ui界面通过回调函数取到ping任务所返回的数据。

1、需要创建一个定义函数指针的方式:

        回调类型确定:typedef void (*VCD_PING_CALLBACK)(StVcdPingVar* ctx);

StVcdPingVar代表函数指针指向的函数(回调函数)所需要的参数,做完这一步,就可以用VCD_PING_CALLBACK去定义函数指针了。下面是回调函数参数类型:确定取回三个数据,延迟、丢包以及额外自定义数据。

typedef struct st_vcd_ping{
    float delay;
    int pkt_loss_rate;
    gpointer priv;
}StVcdPingVar;

        回调函数实现:很简单,取回的数据在此处打印即可,要是有界面程序可以将数据传入界面以显示,M_DBEUG是自己实现的printf,大家可以用printf代替。

static void vcd_ping_callback(StVcdPingVar *data) {

    StVcdPingVar *ctx = (StVcdPingVar *)data;
    M_DEBUG("vcd_ping_callback delay:%d,loss:%d\n", ctx->delay, ctx->pkt_loss_rate);
}

2、实现ping任务

        总览:一般来说我们采取一个c++中的单例模式,启动一个ping的任务,用一个源文件和一个头文件实现,对外只公开ping任务开启和关闭的接口,并且在开启任务的时候将实现好的回调函数传入这个任务,待任务完成时自动调用这个函数以更新数据。

        数据结构:一个单例所用的到的所有数据我们可以存放在一个静态全局的结构体中,这个g_ping_ctx只供这个文件使用(对外不显示),结构里面存放了线程句柄,线程结束标志位,回调函数指针,以及用户自定义数据等等。

typedef struct st_vcd_ping_linux{
    VCD_PING_CALLBACK func;
    GThread *thd;
    gpointer priv;
    gboolean bStop;
}VcdPingLinuxCtx;

static VcdPingLinuxCtx* g_ping_ctx;

        开启ping任务:  下面是开启ping任务的入口,可以看到参数用VCD_PING_CALLBACK来接入。调用的时候只要将上面实现的vcd_ping_callback函数名传入即可。

static gboolean vcd_ping_linux_start(VCD_PING_CALLBACK func,gpointer priv){

    if (g_ping_ctx)
        vcd_ping_linux_stop();
    M_DEBUG("vcd_ping_linux_start");
    g_ping_ctx = g_malloc0(sizeof(VcdPingLinuxCtx));

    g_ping_ctx->priv = priv;
    g_ping_ctx->func = func;

    g_ping_ctx->thd = g_thread_new("vcd_ping_linux", (GThreadFunc)GThreadFunc_ping, NULL);

    return TRUE;
}

        下面就是ping线程的实现方式:取回数据之后用g_ping_ctx->func(&ctx);调用回调函数即会在之前的M_DEBUG中显示了。

static gpointer GThreadFunc_ping(gpointer arg){

    while(g_ping_ctx && !g_ping_ctx->bStop){

        char* host = g_vcd_conf->ip;
        if(!host) goto fail;

        char cmd[100] = {0};
        snprintf(cmd, sizeof(cmd), "ping -c 4 -W 1 %s", host);

        FILE* pf = popen(cmd, "r");
        if(!pf) goto fail;

        const int len = 1024;
        char data[1024] = {0};

        int loss = -1;
        float delay = -1;

        while(fgets((char*)data, len, pf)){
            //M_DEBUG("fgets:%s",data);
            if(is_packet_loss_str(data))
                loss = find_packet_loss(data);
            if(is_avg_delay_str(data))
                delay = find_avg_delay(data);
        }

        if(loss != -1 && delay != -1 && g_ping_ctx && g_ping_ctx->func){
            StVcdPingVar ctx = {0};
            ctx.delay = delay;
            ctx.pkt_loss_rate = loss;
            ctx.priv = g_ping_ctx->priv;
            g_ping_ctx->func(&ctx);
        }
        pclose(pf);
        continue;
fail:
        sleep(1);
        continue;
    }
    return FALSE;
}

        最后给上任务结束函数:

static void vcd_ping_linux_stop(){

    g_return_if_fail(g_ping_ctx != 0);
    M_DEBUG("vcd_ping_linux_stop");
    g_ping_ctx->bStop = TRUE;
    system("killall ping");
    g_thread_join(g_ping_ctx->thd);
    g_free(g_ping_ctx);
    g_ping_ctx = 0;
}

        取数据细节函数:

static gboolean is_packet_loss_str(const char* data){
    if(!data) return FALSE;

    const char* sub = "packet loss";
    if(strstr(data,sub)){
        return TRUE;
    }
    return FALSE;
}
// rtt min/avg/max/mdev = 0.578/0.598/0.625/0.019 ms
static gboolean is_avg_delay_str(const char* data){
    if(!data) return FALSE;

    const char* sub = "rtt min/avg/max/mdev = ";
    if(strstr(data,sub)){
        return TRUE;
    }
    return FALSE;
}

static int find_packet_loss(const char* data){

    if(!is_packet_loss_str(data)){
        goto fail;
    }

    const char* sub = "received, ";
    char* pStar = strstr(data,sub);
    if(!pStar) goto fail;

    pStar += strlen(sub);

    char* pEnd  = strstr(pStar,"%");
    if(!pEnd)  goto fail;

    char tmp[10] = {0};
    strncpy(tmp,pStar,pEnd-pStar);

    int loss = atoi(tmp);
    return loss;
fail:
    return -1;
}
// rtt min/avg/max/mdev = 0.578/0.598/0.625/0.019 ms
static float find_avg_delay(const char* data){
    if(!is_avg_delay_str(data)){
        goto fail;
    }

    const char* sub = "rtt min/avg/max/mdev = ";
    char* pStar = strstr(data,sub);
    if(!pStar) goto fail;

    // 0.578/0.598/0.625/0.019 ms
    pStar += strlen(sub);

    pStar = strstr(pStar,"/");
    if(!pStar) goto fail;

    // 0.598/0.625/0.019 ms
    pStar = pStar + 1;

    char* pEnd  = strstr(pStar,"/");
    if(!pEnd)  goto fail;

    char tmp[10] = {0};
    strncpy(tmp,pStar,pEnd-pStar);

    float delay = atof(tmp);

    return delay;
fail:
    return -1;
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言回调函数机制是一种常见的编程模式,它允许在程序执行过程中将函数作为参数传递给其他函数,并在需要时被调用。 回调函数通常用于异步编程或事件驱动的场景中,其中一个函数(通常称为回调函数)在特定事件发生时被调用。在这种情况下,主要的函数会注册回调函数并等待事件发生,当事件触发后,回调函数会被调用来处理事件。换句话说,回调函数是由其他代码控制执行的函数。 在C语言中,回调函数通过函数指针来实现。函数指针是指向函数的指针变量,可以作为参数传递给其他函数,并在需要时被调用。通常,主函数将回调函数作为参数传递给其他函数,然后在适当的时候调用回调函数。 以下是一个简单的示例,演示了C语言中的回调函数机制: ```c #include <stdio.h> // 回调函数 void callback(int num) { printf("Callback function called with number: %d\n", num); } // 接受回调函数作为参数的函数 void performOperation(int num, void (*callback)(int)) { // 执行某些操作 printf("Performing operation with number: %d\n", num); // 调用回调函数 callback(num); } int main() { int number = 10; // 调用 performOperation 函数并传递回调函数 performOperation(number, callback); return 0; } ``` 在上面的示例中,`callback` 函数是一个简单的回调函数,它接受一个整数参数并打印出来。`performOperation` 函数接受一个整数和一个函数指针作为参数,执行某些操作后调用回调函数。 在 `main` 函数中,我们定义了一个整数 `number`,然后调用 `performOperation` 函数并传递 `callback` 函数作为参数。运行程序后,会先执行 `performOperation` 函数中的操作,然后调用回调函数 `callback` 来处理事件,打印出传递的数字。 这只是回调函数机制的一个简单示例,实际应用中回调函数的用途可能更加复杂。通过回调函数机制,我们可以实现灵活的程序设计和事件处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值