欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 幼教 > Linux应用开发实验班——JSON-RPC

Linux应用开发实验班——JSON-RPC

2024/10/23 23:30:03 来源:https://blog.csdn.net/m0_75183905/article/details/142458984  浏览:    关键词:Linux应用开发实验班——JSON-RPC

目录

前言

1.是什么JSON-RPC

2.常用的JSON函数

1.创建JSON

2.根据名字获取JSON

3.获取JSON的值

4.删除JSON

3.如何进行远程调用

服务器

客户端

4.基于JSON-RPC进行硬件操作

课程链接


前言

学习的课程是百问网韦东山老师的课程,对更详细步骤感兴趣的同学,可以去学习视频课程。代码里的led和dht11的驱动都是学习韦老师的课程写的。

1.是什么JSON-RPC

JSON(JavaScript Object Notation,JavaScript 对象表示法)是基于 ECMAScript的
一个子集设计的,是一种开放标准的文件格式和数据交换格式,它易于人阅读和编写,同
时也易于机器解析和生成。JSON独立于语言设计,很多编程语言都支持JSON格式的数据交
换。JSON 是一种常用的数据格式,在电子数据交换中有多种用途,包括与服务器之间的
Web 应用程序的数据交换。其简洁和清晰的层次结构有效地提升了网络传输效率,使其成
为理想的数据交换语言。其文件通常使用扩展名.json。 

1.它的关键成员是“name:value”,value有多种形式。

{ "name": "John", "age": 30, "isStudent": false , "ptr": null }

2.上述例子中,有3种取值:"John"是字符串,30是整数,false是bool类型,null是 空值。 值的类型也可以是数组,比如:

{ "fruits": ["apple","banana", "cherry"] }

3.值的类型,还可以是一个JSON对象,比如:

{

"title":"JSON Example",

"author": { "name":"John Doe", "age": 35, "isVerified":true }, "tags":["json", "syntax", "example"],

"rating": 4.5, "isPublished":false,

"comments": null

}

2.常用的JSON函数

1.创建JSON

使用字符串创建一个cJSON结构体:

cJSON *json = cJSON_Parse(const char *value);
参数:
const char *value:这是唯一的参数,是一个指向要解析的 JSON 字符串的指针。
该字符串需要以 null 结尾。
返回值:
如果解析成功,函数会返回一个指向 cJSON 结构体的指针。
这个结构体表示了解析后的 JSON 数据,可以通过其他 cJSON 库提供的函数
(如 cJSON_GetObjectItem 等)来访问和操作其中的具体元素。
如果解析失败,函数会返回 NULL。导致解析失败的原因可能是 JSON 字符串的格式不正确、
存在非法字符或其他不符合 JSON 规范的情况。
注意事项:使用 cJSON_Parse 函数时,在调用之后一定要检查返回值是否为 NULL,
以确保解析成功。并且在使用完解析后的 cJSON 结构体后,
需要调用 cJSON_Delete 函数来释放内存,以避免内存泄漏。

2.根据名字获取JSON

cJSON *value = cJSON_GetObjectItem(const cJSON * const object, const char * const string);
参数:
const cJSON * const object:这是一个指向 cJSON结构体的常量指针,
代表待查找的 JSON 对象。该参数指定了在哪个 JSON 对象中进行成员查找。
const char * const string:这是一个指向字符串的常量指针,
代表要查找的成员的名称。该名称应与 JSON 对象中成员的键相对应。
返回值:
如果在给定的 JSON对象中找到了指定名称的成员,则返回一个指向该成员的 cJSON结构体的指针。
通过这个返回的指针,可以进一步访问该成员的具体信息,如值的类型、字符串值、数值等。
如果没有找到指定名称的成员,则返回 NULL。所以在使用该函数后,
通常需要检查返回值是否为 NULL,以确保能够正确地处理查找结果。

3.获取JSON的值

cJSON 结构体里存有值:valuestring、valueint、valuedouble,直接使用即可: 

示例:

4.删除JSON

cJSON_public(void) cJSON_Delete(cJSON *item);
参数:
cJSON *item:这是一个指向要释放的 cJSON 结构体的指针。
该指针指向的 cJSON 结构体可以是由 cJSON_Parse 函数解析 JSON 字符串后得到的根节点,
也可以是通过其他 cJSON 函数获取的子节点。
返回值:该函数没有明确的特定返回值类型定义,其主要作用是释放内存。
在调用该函数后,传入的 cJSON 结构体指针 item 及其所有相关的子结构体所占用的内存都会被释放。

3.如何进行远程调用

服务器

服务器的编写json-rpc为我们提供了初始化的API接口,直接调用就可以进行初始化。

1.初始化

函数原型:
int jrpc_server_init(struct jrpc_server *server, int port_number)。
参数:
struct jrpc_server *server:这是一个指向jrpc_server结构体的指针,
用于传递服务器的配置信息和状态。通过这个参数,函数可以对服务器进行初始化设置。
int port_number:指定服务器要监听的端口号。
返回值:
返回一个整数。具体的返回值含义可能取决于函数的具体实现逻辑。
通常情况下,可能返回一些状态码,比如成功初始化时返回 0,
出现错误时返回非零值以表示不同类型的错误情况。

2.在服务器上注册新的过程 

函数原型:
int jrpc_register_procedure(struct jrpc_server *server, jrpc_function function_pointer, char *name, void *data)。
参数:
struct jrpc_server *server:指向 JSON-RPC 服务器结构体的指针,
用于在该服务器上注册新的过程。
jrpc_function function_pointer:一个函数指针,指向要注册的过程所对应的函数。
char *name:要注册的过程的名称。
void *data:一个通用指针,可以传递与注册的过程相关的额外数据。
返回值:
返回一个整数。如果注册成功,返回 0;如果出现错误,
比如内存分配失败或字符串复制失败,返回 -1。

3.启动 JSON-RPC 服务器

函数原型:
void jrpc_server_run(struct jrpc_server *server)。
参数:
struct jrpc_server *server:指向 JSON-RPC 服务器结构体的指针。
这个结构体中包含了与服务器运行相关的信息,特别是其中的事件循环(通过server->loop访问)。
返回值:
无返回值(void)。

服务器会监听设置的端口,根据客户端发送来的消息选择要执行的过程,将数据以cjson结构体返回 

4.在服务器不再使用时进行清理和资源释放操作

函数原型:
void jrpc_server_destroy(struct jrpc_server *server)。
参数:
struct jrpc_server *server:指向 JSON-RPC 服务器结构体的指针。
这个结构体包含了服务器运行时的各种状态和资源信息。
返回值:
无返回值(void)。

客户端

客户端的编写,初始化和之前网络编程中的客户端编写是相同的。

初始化

这里我就直接放代码了,不懂可以查看直接网络编程那一篇的文章

int RPC_Client_Init(void) 
{int iSocketClient;struct sockaddr_in tSocketServerAddr;int iRet;iSocketClient = socket(AF_INET, SOCK_STREAM, 0);tSocketServerAddr.sin_family      = AF_INET;tSocketServerAddr.sin_port        = htons(PORT);  /* host to net, short *///tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;inet_aton("127.0.0.1", &tSocketServerAddr.sin_addr);memset(tSocketServerAddr.sin_zero, 0, 8);iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	if (-1 == iRet){printf("connect error!\n");return -1;}return iSocketClient;    
}

客户端选择要远程调用的过程

1.将消息构造成json类型的字符串,发送给给服务器

 sprintf(buf, "{\"method\": \"add\", \"params\": [%d,%d], \"id\": \"2\" }", a, b);iLen = send(iSocketClient, buf, strlen(buf), 0);

2.服务器会返回一个cjson结构体的结果,解析cjson结构体获取结果

iLen = read(iSocketClient, buf, sizeof(buf));
cJSON *root = cJSON_Parse(buf);
cJSON *result = cJSON_GetObjectItem(root, "result");
*sum = result->valueint;
cJSON_Delete(root);

4.基于JSON-RPC进行硬件操作

服务器端:
 

#include <jsonrpc-c.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "rpc.h"
#include "led.h"
#include "dht11.h"static struct jrpc_server my_server;/* 参数: {"params" : [0|1]} */
cJSON * server_led_control(jrpc_context * ctx, cJSON * params, cJSON *id) {cJSON * status = cJSON_GetArrayItem(params,0);led_control(status->valueint);	return cJSON_CreateNumber(0);
}/* 参数: {"params" : null} */
cJSON * server_dht11_read(jrpc_context * ctx, cJSON * params, cJSON *id) {int array[2];array[0] = array[1] = 0;while (0 != dht11_read((char *)&array[0], (char *)&array[1]));return cJSON_CreateIntArray(array, 2);
}int RPC_Server_Init(void) 
{int err;err = jrpc_server_init(&my_server, PORT);if (err){printf("jrpc_server_init err : %d\n", err);}jrpc_register_procedure(&my_server, server_led_control, "led_control", NULL );jrpc_register_procedure(&my_server, server_dht11_read, "dht11_read", NULL );jrpc_server_run(&my_server);jrpc_server_destroy(&my_server);return 0;
}int main(int argc, char **argv)
{led_init();dht11_init();RPC_Server_Init();   return 0;
}

客户端:

#include <jsonrpc-c.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "rpc.h"int rpc_led_control(int iSocketClient, int on)
{char buf[100];int iLen;int ret = -1;sprintf(buf, "{\"method\": \"led_control\", \"params\": [%d], \"id\": \"2\" }", on);iLen = send(iSocketClient, buf, strlen(buf), 0);if (iLen ==  strlen(buf)){while (1) {iLen = read(iSocketClient, buf, sizeof(buf));buf[iLen] = 0;if (iLen == 1 && (buf[0] == '\r' || buf[0] == '\n'))continue;elsebreak;} if (iLen > 0){cJSON *root = cJSON_Parse(buf);cJSON *result = cJSON_GetObjectItem(root, "result");ret = result->valueint;cJSON_Delete(root);return ret;}else{printf("read rpc reply err : %d\n", iLen);return -1;}}else{printf("send rpc request err : %d, %s\n", iLen, strerror(errno));return -1;}
}int rpc_dht11_read(int iSocketClient, char *humi, char *temp)
{char buf[300];int iLen;sprintf(buf, "{\"method\": \"dht11_read\"," \"\"params\": [0], \"id\": \"2\" }");        iLen = send(iSocketClient, buf, strlen(buf), 0);if (iLen ==  strlen(buf)){while (1) {iLen = read(iSocketClient, buf, sizeof(buf));buf[iLen] = 0;if (iLen == 1 && (buf[0] == '\r' || buf[0] == '\n'))continue;elsebreak;} if (iLen > 0){cJSON *root = cJSON_Parse(buf);cJSON *result = cJSON_GetObjectItem(root, "result");if (result){cJSON * a = cJSON_GetArrayItem(result,0);cJSON * b = cJSON_GetArrayItem(result,1);*humi = a->valueint;*temp = b->valueint;cJSON_Delete(root);return 0;}else{cJSON_Delete(root);return -1;}}else{printf("read rpc reply err : %d\n", iLen);return -1;}}else{printf("send rpc request err : %d, %s\n", iLen, strerror(errno));return -1;}
}/* 连接RPC Server* 返回值: (>0)socket, (-1)失败*/
int RPC_Client_Init(void) 
{int iSocketClient;struct sockaddr_in tSocketServerAddr;int iRet;iSocketClient = socket(AF_INET, SOCK_STREAM, 0);tSocketServerAddr.sin_family      = AF_INET;tSocketServerAddr.sin_port        = htons(PORT);  /* host to net, short *///tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;inet_aton("127.0.0.1", &tSocketServerAddr.sin_addr);memset(tSocketServerAddr.sin_zero, 0, 8);iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	if (-1 == iRet){printf("connect error!\n");return -1;}return iSocketClient;    
}static void print_usage(char *exec)
{printf("Usage:\n");printf("%s led <0|1>\n", exec);printf("%s dht11\n", exec);
}int main(int argc, char **argv)
{if (argc < 2){print_usage(argv[0]);return -1;}{        int sum;int fd = RPC_Client_Init();if (fd < 0){printf("RPC_Client_Init err : %d\n", fd);return -1;}if (argc == 3 && !strcmp(argv[1], "led")){int on = (int)strtoul(argv[2], NULL, 0);int err = rpc_led_control(fd, on);if (!err){printf("set led ok\n");}else{printf("rpc err : %d\n", err);}}else if (argc == 2 && !strcmp(argv[1], "dht11")){            char humi, temp;int err = rpc_dht11_read(fd, &humi, &temp);if (err){printf("rpc err : %d\n", err);}else{printf("dht11 humi = %d, temp = %d\n", humi, temp);}}            }return 0;
}

课程链接

Linux应用入门实验班icon-default.png?t=O83Ahttps://video.100ask.net/p/t_pc/course_pc_detail/video/v_66e049f8e4b023c061203dd5?product_id=p_66e0497de4b023c06c8ea08d&content_app_id=&type=6

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com