当前位置: 首页 > news >正文

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

相关文章:

  • 大数据新视界 --大数据大厂之HBase 在大数据存储中的应用与表结构设计
  • 【有啥问啥】“弱激励学习(Weak Incentive Learning)”的原理与过程解析
  • 如何使用ssm实现基于SpringMVC网上选课系统的设计与实现
  • 努比亚z17努比亚NX563j原厂固件卡刷包下载_刷机ROM固件包下载-原厂ROM固件-安卓刷机固件网
  • Python图形用户界面设计的15个基础组件
  • 代码编码规范文档(参考)
  • GPT实现联网,NextChat插件的配置说明
  • 理解和使用语言模型的监督微调 (SFT)
  • 贷款并非只看利息低,还有很多你知不道的地方
  • 探索未来IT技术的浩瀚星河:一场跨越时代的数字盛宴
  • 沉浸式艺术创作:FLUX.1模型下的Java开发者体验之旅
  • python基础之绘图turtle与分词
  • HarmonyOS鸿蒙开发实战(5.0)自定义路由栈管理
  • c# 将调试信息到VS输出窗口
  • Thingsboard规则链:fetch device credentials节点详解
  • 网络传输文件的问题
  • SegmentFault for Android 3.0 发布
  • C++11: atomic 头文件
  • canvas 五子棋游戏
  • Date型的使用
  • If…else
  • MySQL的数据类型
  • SpiderData 2019年2月16日 DApp数据排行榜
  • ubuntu 下nginx安装 并支持https协议
  • vue:响应原理
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 对超线程几个不同角度的解释
  • 关于字符编码你应该知道的事情
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 蓝海存储开关机注意事项总结
  • 树莓派 - 使用须知
  • 小程序开发中的那些坑
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • (JS基础)String 类型
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (原創) 系統分析和系統設計有什麼差別? (OO)
  • (轉貼) UML中文FAQ (OO) (UML)
  • ../depcomp: line 571: exec: g++: not found
  • .bat批处理(一):@echo off
  • .NET : 在VS2008中计算代码度量值
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • .NET/C#⾯试题汇总系列:集合、异常、泛型、LINQ、委托、EF!(完整版)
  • .NET开发人员必知的八个网站
  • :not(:first-child)和:not(:last-child)的用法
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • @ohos.systemParameterEnhance系统参数接口调用:控制设备硬件(执行shell命令方式)
  • @RequestParam详解
  • @vue/cli脚手架
  • [20190113]四校联考
  • [AWS]CodeCommit的创建与使用