最近在做嵌入式软件开发的时候,在思考如何将功能接口暴露给其他的应用接口和测试程序呢?特别时在跨语言的时候,如何实现其他应用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函数。