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

news2024/12/23 6:40:55

目录

前言

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;
            else
                break;
        } 
        
        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;
            else
                break;
        } 
        
        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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2164642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LINUX网络编程:Tcp(2)

目录 1.Tcp流量控制 2.滑动窗口 2.1滑动窗口的更新 2.2滑动窗口的丢包问题 1.报文丢失的情况 2.ACK丢失的情况 3.拥塞控制 3.1慢启动 3.2拥塞窗口的增长 1.Tcp流量控制 为什会有流量控制&#xff1f; 1.在网络通信中&#xff0c;假如发送方的发送能力特别的强&#xff0…

支付宝沙箱环境 支付

一 什么是沙箱&#xff1a; 沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境 支付宝正式和沙箱环境的区别 &#xff1a; AI&#xff1a; 从沙箱到正式环境&#xff1a; 当应用程序开发完成后&#xff0c;需要将应用程序从沙箱环境迁移到正式环境。 这通常涉及…

opencv图像增强十四:opencv两种白平衡介绍及实现

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、白平衡介绍二、灰度世界法三、完美反射法 前言 在摄影与影像领域&#xff0c;白平衡是一个至关重要的概念。它直接影响着画面的色彩表现&#xff0c;关系到…

构建网络遇到的问题-AlexNet

1.对模型进行初始化采用的一般代码 def _initialize_weights(self):for m in self.modules(): # 遍历模型每一层if isinstance(m, nn.Conv2d): # 判定m层是否属于nn.Conv2d类型nn.init.kaiming_normal_(m.weight, modefan_out, nonlinearityrelu)if m.bias is not None:nn.in…

从自动化到智能化:AI如何推动业务流程自动化

引言&#xff1a;从自动化到智能化的必然趋势 在当今数字化时代&#xff0c;企业为了提升效率、降低成本&#xff0c;纷纷采用自动化技术来简化重复性任务。然而&#xff0c;传统自动化仅限于标准化操作&#xff0c;无法应对复杂的决策和多变的市场环境。随着人工智能&#xff…

基于springboot垃圾分类网站

基于springboot垃圾分类网站 摘 要 本论文主要论述了如何使用JAVA语言开发一个垃圾分类网站 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述垃圾分类网站的当…

Android开发拍身份证带人像框和国徽框效果

Android开发拍身份证带人像框和国徽框效果 拍身份证时往往要带上外框辅助用户拍照&#xff0c;这也是很常见的需求。 一、思路 自定义Camera和自定义拍照的界面&#xff0c;把外框画上去&#xff0c;做个遮罩 二、效果图&#xff1a; Android开发教程实战案例源码分享-拍身…

深入理解计算机系统-Bomb Lab

使用 头歌 平台 GDB 调试器 反汇编函数

动力锂电池电芯壳体市场前景:预计2030年全球市场规模将达到49.2亿美元

动力锂电池罐起着传输能量、承载电解液、保护安全等重要作用&#xff0c;是锂电池的重要组成部分。 据QYResearch调研团队最新报告“全球动力锂电池电芯壳体市场报告2024-2030”显示&#xff0c;预计2030年全球动力锂电池电芯壳体市场规模将达到49.2亿美元&#xff0c;未来几年…

分布式算法

分布式场景下的核心问题 分布式场景下困扰我们的3个核心问题&#xff08;CAP&#xff09;&#xff1a;一致性、可用性、分区容错性。 1、一致性&#xff08;Consistency&#xff09;&#xff1a;无论服务如何拆分&#xff0c;所有实例节点同一时间看到是相同的数据。 2、可用性…

开源链动 2+1 模式 S2B2C 商城小程序:社交电商团队为王的新引擎

摘要&#xff1a;本文深入探讨在社交电商领域中&#xff0c;团队的重要性以及如何借助开源链动 21 模式 S2B2C 商城小程序&#xff0c;打造具有强大竞争力的团队&#xff0c;实现个人价值与影响力的放大&#xff0c;创造被动收入&#xff0c;迈向财富自由之路&#xff0c;同时为…

从汽车高速线束角度浅谈中控屏黑屏、闪屏及信号阈值低故障-之AEM线束测试仪应用案例

故障成因和解决方案 随着车载信息娱乐技术的迅速发展&#xff0c;中控屏已经成为现代汽车的标配。然而&#xff0c;许多主机厂和消费者在车辆使用过程中常常遇到中控屏出现黑屏、闪屏以及信号阈值低等问题&#xff0c;给使用带来了诸多困扰。本文将从汽车高速线束的角度&#…

GPU服务器本地搭建Dify+xinference实现大模型应用

文章目录 前言一、显卡驱动配置1.检测显卡2.安装驱动 二、安装nvidia-docker二、安装Xinference1.拉取镜像2.运行Xinference3.模型部署 三、安装Dify1.下载源代码2.启动 Dify3.访问 Dify 四、Dify构建应用1.配置模型供应商2.聊天助手3.Agent 前言 本文使用的GPU服务器为UCloud…

MySQL: 数据类型介绍

文章目录 数据类型数值类型字符串类型日期类型 数据类型 数值类型 分为整型和浮点型: BIT类似于数据结构中的位图,BIT可以认为是一组二进制bit位. BIT(10)表示这个类型里就存最多10个bit位. 虽然TINYINT和SMALLINT更节省空间,但是还是更推荐使用INT或者BIGINT. 如果存储空间…

MySql语言操作数据库---增删改查数据库,表,数据

思维导图 SQL语言共分为四大类&#xff1a; 数据定义语言DDL:数据定义语言DDL用来创建数据库中的各种对象-----[库]、[表]、[视图]、[索引]、 数据操纵语言DML:(1) 插入&#xff1a;INSERT (2) 更新&#xff1a;UPDATE (3) 删除&#xff1a;DELETE 数据查询语言DQL:数据查询语…

Android 深层链接利用

为了能够从我们的应用程序打开另一个应用程序&#xff0c;我们通常通过声明我们想要访问的 Activity 类的名称来实现这一功能。但是&#xff0c;如果我们要打开的 Activity 在其清单文件中设置了android:exported"false" &#xff0c;则无法使用此方法。而其中一种替…

人工智能有助于解决 IT/OT 集成安全挑战

思科的一项研究表明&#xff0c;信息技术 (IT) 和运营技术 (OT) 融合所带来的安全问题可以通过人工智能 (AI) 解决&#xff0c;尽管该技术也可能被恶意行为者利用。 该报告由思科和 Sapio Research 联合发布&#xff0c;对 17 个国家的 1,000 名行业专业人士进行了调查&#x…

基于Java,SpringBoot和Vue的仓库管理商品管理电商后台管理系统

摘要 基于Java、Spring Boot和Vue的仓库管理系统是一个现代化的库存管理解决方案&#xff0c;旨在提高仓库运营效率和准确性。系统采用Java作为后端开发语言&#xff0c;结合Spring Boot框架简化配置和部署过程&#xff0c;实现业务逻辑和数据处理。前端使用Vue.js构建用户界面…

2024.9.25 数据分析学习

资料&#xff1a; 【开课吧哩堂】数据挖掘项目之用户流失预警系统_哔哩哔哩_bilibili 五万字 | Spark吐血整理&#xff0c;学习与面试收藏这篇就够了&#xff01;-腾讯云开发者社区-腾讯云 (tencent.com) 黑马程序员Spark全套视频教程&#xff0c;4天spark3.2快速入门到精通…

**CentOS7安装配置mysql**

CentOS7安装配置mysql 首先先将mysql57-community-release-el7.rpm解压出来 rpm -ivh mysql57-community-release-el7.rpmls /etc/yum.repos.d/ -l // 检查是否解压成功安装mysql yum install -y mysql-community-server可能会出现 GPG 密钥过期 rpm --import https://r…