最近在做嵌入式软件开发的时候,在思考如何将功能接口暴露给其他的应用接口和测试程序呢?特别时在跨语言的时候,如何实现其他应用app的调用呢,虽然使用C开发的程序,应该都可以被其他的的应用程序调用,当然这个时在提供头文件和情况下,但是我想要实现,该接口不仅可以通过本地接口的形式进行调用,也通过某种的形式进行远程调用。
远程服务调用的思想,其实在之前就已经有了,不过远程调用大部分的实现形式是面向对象的高级语言的,没有找到一个合适的,面向过程语言的。然后在网上查找资料,看到一个使用json的demo。链接如下:请输入链接描述

该代码实现了一个简单的json rpc的server demo。该demo使用了cjson库和libev库,进行相关的实现,但是我现在不想使用libev库来实现该程序,因此我想要通过libuv来做tcp协议的相关处理和cjson进行配合实现。

对外接口的实现


sint32 jrpc_open(int port_number)
{
    PJSONRPC_FD_S fd = &rpc_fd;
    int rtval = 0;

    if (FLAG_VERIFY(fd))
    {
        JRPC_TRACE_ERR("handle opened\n");
        return ERRNO(COMMON_ERROR_HANDLEOPEND, COMP_NENT);
    }

    memset(fd, 0x00, JSONRPC_FD_S_LEN);

    // fd->uv_loop = uv_default_loop();
    if (NULL == ( fd->uv_loop =
        JRPC_MALLOC(sizeof(uv_loop_t)) ) )
    {
        rtval = ERRNO(COMMON_ERROR_NOMEM, COMP_NENT);
        goto error;
    }

    if (NULL == ( fd->psenf_buff =
        JRPC_MALLOC(JSON_RPC_SENDBUFF_MAX ) ) )
    {
        rtval = ERRNO(COMMON_ERROR_NOMEM, COMP_NENT);
        goto error;
    }

    if (NULL == ( fd->precv_buff =
        JRPC_MALLOC( JSON_RPC_RECVBUFF_MAX ) ) )
    {
        rtval = ERRNO(COMMON_ERROR_NOMEM, COMP_NENT);
        goto error;
    }

    uv_loop_init(fd->uv_loop);

    uv_tcp_init(fd->uv_loop, &fd->server);
    uv_ip4_addr("0.0.0.0", port_number, &fd->sock_addr);
    rtval = uv_tcp_bind(&fd->server, (const struct sockaddr*)&fd->sock_addr, 0);

    if( rtval < 0 ){
        fprintf(stderr,"bind addr 9090 error!\n");
        return 1;
    }

    int r = uv_listen((uv_stream_t*) &fd->server, DEFAULT_BACKLOG, on_new_connection);
    fd->port_number = port_number;
    if (r)
    {
        fprintf(stderr, "Listen error %s\n", uv_strerror(r));
        return -1;
    }

    pthread_mutex_init(&fd->mtx, NULL);

    fd->flag = COMP_FLAG;
    fd->debug_level = 1;

    cli_reg(jrpc_cli);
    JRPC_TRACE_DBG("json rpc module open success fd:%d\n", (sint32)fd);

    return (sint32)fd;
error:
    JRPC_FREE(fd->uv_loop);
    JRPC_FREE(fd->precv_buff);
    JRPC_FREE(fd->psenf_buff);
    return rtval;
}

/******************************************************************************
 * 函数介绍: 启动模块
 * 输入参数: handle: 模块句柄,此处无效
 *           priority: 线程优先级1~99
 * 输出参数: 无
 * 返回值  : 0-成功,<0-错误代码
 *****************************************************************************/
sint32 jrpc_start(sint32 handle, sint32 priority)
{
    PJSONRPC_FD_S fd = &rpc_fd;
    sint32 rtval = 0;

    if (0 == FLAG_VERIFY(fd))
    {
        JRPC_TRACE_ERR("handle is invalid\n");
        return ERRNO(COMMON_ERROR_HANDLEINVAL, COMP_NENT);
    }

    if (fd->running)
    {
        JRPC_TRACE_ERR("thread is started\n");
        return ERRNO(COMMON_ERROR_THREADSTARTED, COMP_NENT);
    }
    else
    {
        if ((rtval = pthread_start((sint32 *)&fd->tid, priority, (void *)_jrpc_body, 0)) < 0)
        {
            PERROR(rtval);
            fd->running = 0;
            return ERRNO(COMMON_ERROR_THREADSTART, COMP_NENT);
        }
        else
        {
            while ((0 == fd->running) && (0 == fd->healthy))
            {
                sleep_ms(10);
            }
        }

    }

    return rtval;
}

sint32 jrpc_close()
{
    PJSONRPC_FD_S fd = &rpc_fd;
    int i = 0;

    if (0 == FLAG_VERIFY(fd))
    {
        JRPC_TRACE_ERR("handle is invalid\n");
        return ERRNO(COMMON_ERROR_HANDLEINVAL, COMP_NENT);
    }

    if(fd->running)
    {
        fd->running = 0;
        sleep(1);
    }

    JRPC_FREE(fd->uv_loop);
    JRPC_FREE(fd->precv_buff);
    JRPC_FREE(fd->psenf_buff);

    for (i = 0; i < fd->procedure_count; i++){
        jrpc_procedure_destroy( &(fd->procedures[i]) );
    }

    JRPC_FREE(fd->procedures);
    memset(fd, 0x00, JSONRPC_FD_S_LEN);
}

这几个接口主要是实现一些对外的功能。包括模块的打开和关闭等。

sint32 jrpc_register_procedure(jrpc_function function_pointer, char *name, void * data)
{
    PJSONRPC_FD_S fd = &rpc_fd;

    int i = fd->procedure_count++;
    if (!fd->procedures)
        fd->procedures = JRPC_MALLOC(sizeof(struct jrpc_procedure));
    else {
        struct jrpc_procedure * ptr = JRPC_REALLOC(fd->procedures,
                sizeof(struct jrpc_procedure) * fd->procedure_count);
        if (!ptr)
            return -1;
        fd->procedures = ptr;

    }
    if ((fd->procedures[i].name = strdup(name)) == NULL)
        return -1;
    fd->procedures[i].function = function_pointer;
    fd->procedures[i].data = data;
    return 0;
}

sint32 jrpc_deregister_procedure(char *name)
{
    PJSONRPC_FD_S fd = &rpc_fd;

    /* Search the procedure to deregister */
    int i;
    int found = 0;
    if (fd->procedures){
        for (i = 0; i < fd->procedure_count; i++){
            if (found)
                fd->procedures[i-1] = fd->procedures[i];
            else if(!strcmp(name, fd->procedures[i].name)){
                found = 1;
                jrpc_procedure_destroy( &(fd->procedures[i]) );
            }
        }
        if (found){
            fd->procedure_count--;
            if (fd->procedure_count){
                struct jrpc_procedure * ptr = JRPC_REALLOC(fd->procedures,
                    sizeof(struct jrpc_procedure) * fd->procedure_count);
                if (!ptr){
                    perror("realloc");
                    return -1;
                }
                fd->procedures = ptr;
            }else{
                fd->procedures = NULL;
            }
        }
    } else {
        fprintf(stderr, "server : procedure '%s' not found\n", name);
        return -1;
    }
    return 0;
}

这几个接口主要是实现rpc的相关业务逻辑功能,主要是生成者和消费者模型。


static void *_jrpc_body(void *arg)
{
    PJSONRPC_FD_S fd = &rpc_fd;
    sint32 rtval = 0;

    fd->pid = getpid();
    fd->healthy = 0;
    fd->running = 1;
    JRPC_TRACE_DBG("_jrpc_body PID(%d) OK\n",fd->pid);

    if ((rtval = pthread_set_thread_name("_jrpc_body")) < 0)
    {

        PERROR(rtval);
    }

    JRPC_TRACE_DBG("_JRPC_body start \n");

    while (fd->running)
    {
        uv_run(fd->uv_loop, UV_RUN_DEFAULT);
    }

    JRPC_TRACE_DBG("_jrpc_body down\n");

    pthread_exit(NULL);
}

RPC的run函数。

Last modification:May 29th, 2020 at 10:36 pm
如果觉得我的文章对你有用,请随意赞赏