嵌入式全栈开发学习笔记---Linux常用库(json)

devtools/2024/10/22 15:36:13/

目录

入门级问题

json%3F-toc" style="margin-left:40px;">为什么使用json?

json%3F-toc" style="margin-left:40px;">什么是json?

json-c%E5%BA%93-toc" style="margin-left:0px;">json-c库

json%E6%BA%90%E7%A0%81-toc" style="margin-left:40px;">json源码

安装方法

json-c%20API-toc" style="margin-left:0px;">json-c API

Json类型

C-API

json%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2(json%E5%AF%B9%E8%B1%A1)-toc" style="margin-left:80px;">将一个字符串转换成符合json格式的字符串(json对象)

定义一个字符串数组

json_object%E7%BB%93%E6%9E%84%E4%BD%93%E6%8C%87%E9%92%88-toc" style="margin-left:120px;">定义一个json_object结构体指针

json%E5%AF%B9%E8%B1%A1-toc" style="margin-left:120px;">把一个字符串转换成一个json对象

json%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%9C%B0%E5%9D%80%E7%BB%99%E7%BB%93%E6%9E%84%E4%BD%93%E6%8C%87%E9%92%88-toc" style="margin-left:120px;">将转换成json对象的字符串的地址给结构体指针

json%E6%A0%BC%E5%BC%8F%E7%9A%84json%E5%AF%B9%E8%B1%A1-toc" style="margin-left:80px;">组合json格式的json对象

json%E5%AF%B9%E8%B1%A1-toc" style="margin-left:120px;">第一步,创建空json对象

json%E5%AF%B9%E8%B1%A1%E4%B8%AD%E5%A1%AB%E9%94%AE%E5%80%BC%E5%AF%B9-toc" style="margin-left:120px;">第二步,往空的json对象中填键值对

json%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%AF%B9%E8%B1%A1-toc" style="margin-left:120px;">第三步,将C字符串转换成json字符串格式的对象

json%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%AF%B9%E8%B1%A1-toc" style="margin-left:120px;">第四步,将整数转换成json格式的对象

json%E5%AF%B9%E8%B1%A1-toc" style="margin-left:80px;">解析json对象

json%E5%AF%B9%E8%B1%A1%E8%8E%B7%E5%8F%96%E5%AF%B9%E5%BA%94%E6%95%B0%E6%8D%AE%E7%9A%84json%E5%AF%B9%E8%B1%A1-toc" style="margin-left:120px;">第一步,根据键名,从json对象获取对应数据的json对象

json%E5%AF%B9%E8%B1%A1%E8%BD%AC%E5%8C%96%E4%B8%BA%E5%AF%B9%E5%BA%94%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%95%B0%E6%8D%AE-toc" style="margin-left:120px;">第二步,根据数据类型,将数据对应的json对象转化为对应类型的数据

json%E6%95%B0%E7%BB%84-toc" style="margin-left:80px;">json数组

json%E6%95%B0%E7%BB%84%E5%AF%B9%E8%B1%A1-toc" style="margin-left:120px;">创建json数组对象

往数组里面填充元素

json%E5%AF%B9%E8%B1%A1%E4%B8%AD-toc" style="margin-left:120px;">把数组对象嵌套到json对象中

从对象中把数组对象中每一个元素对象解析出来

json%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93-toc" style="margin-left:0px;">Json-C/S架构json数据传输


目前我们学习完了Linux系统编程和网络编程,现在开始学习linux常用库!

json是一个非常常用的一种库,它跟语言是没有关系的,不仅仅是在C语言里面, 很多语言里面多可以用,它是一种数据包的格式。

入门级问题

json%3F" style="background-color:transparent;margin-left:.0001pt;text-align:left;">为什么使用json?

以QQ注册的场景为例。

当我们注册QQ的时候,我们需要输入很多信息,比如账号,密码还有一些以防之后忘记密码需要找回密码时所需的邮箱账号,或者密保问题等等,这些信息有将放在一个结构体里面,注册成功后,我们登录的时候,就只需要用到账号和密码,那么之前注册的结构体里的其他成员就用不上了,为了节约内存空间只好又重新创建一个登录时用的结构体,这个结构体只放账号和密码,但是这样如果每次一个任务都要重开一个结构体,就太麻烦了。

如果不开新的结构体,之后什么信息都往注册时用的结构体里面添加,这个结构体的体量会变得越来越大,在执行不同的任务时,有可能结构体里面的很多成员是用不上的,这样很浪费资源

json就是为了解决以上这些问题的。Json不像结构体一旦创建,里面的成员就固定了,Json的格式是灵活的。这就是我们在Linux开发里面为什么要使用json的原因,尤其是在CS架构里面,在客户端和服务器进行交互数据的时候,json比结构体更加实用。

json%3F" style="margin-left:.0001pt;text-align:left;">什么是json?

JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。

json其实就是一个键值对

一些合法的Json实例:

{“name”: ”Jack”, ”sex” : ”male”}

{“name”: ”Jack”, ”age” : 18, ”address”: {“country”: “china”, “zip-code”: “10000”}} //json嵌套

{“a”: 1, “b”: [1, 2, 3]}

以上比如name: Jack就是一个json对象,也就是一个键值对,json允许没有“键”,只有“值”,也就是说只有Jack没有name也是可以的。不同的json对象用逗号隔开。一个Json对象内部是用冒号隔开的,json里面嵌套对象用花括号{ }隔开。

json里面无论是字符串还是字符都是用双引号,没有单引号。

json-c%E5%BA%93" style="margin-left:.0001pt;text-align:left;">json-c库

json支持很多种语言

json-c 库中是在嵌入式开发中常用的库。因为很多地方都以json数据数据交互协议, 尤其嵌入式web数据交互时通常会用到json格式, 因此如果需要在产品端进行json数据解析 , json-c 是一个比较不错的选择。

以智能家居的智能开关为例,智能开关和普通的开关相比,它的特别之处在于可以通过手机来控制开/关。手机先把数据发给服务器,服务器再把数据发送到开关上面,开关作为一个嵌入式产品,它要跟服务器不停地进行数据的交互。在嵌入式端我们用到json-c,因为嵌入式端一般都是用C语言来写的,所以需要移植json-c库

json%E6%BA%90%E7%A0%81" style="margin-left:.0001pt;text-align:left;">json源码

链接:https://pan.baidu.com/s/19LJNLTYj--yKWfoYUjt83g

提取码:asn5

安装方法

把上面源码拉到虚拟机上的一个文件夹下,随便一个文件夹都行,路径不指定。然后执行这四句命令就安装成功了。

./autogen.sh

./configure

make

make install

json-c%20API" style="margin-left:.0001pt;text-align:left;">json-c API

Json类型

安装好Json-c之后可以在这个头文件中找到json的类型

支持的对象类型在这个枚举里面

我们常用的就是这个json对象(含有键值对的json对象)

比如这就是一个object类型,

如果只有值,没有键,也可以作为一个json对象,只不过这个json的类型是这个,也就是字符串类型的

还有int,也可以作为json的类型

比如这个json对象的类型就是int,

还有array数组类型

比如

C-API

接下来测试一下将一个字符串转换成符合json格式的json对象

json%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2(json%E5%AF%B9%E8%B1%A1)" style="background-color:transparent;margin-left:.0001pt;text-align:left;">将一个字符串转换成符合json格式的字符串(json对象)

定义一个字符串数组

先定义一个字符串数组

注意,{ }里面的双引号前都要加上转义字符\

json_object%E7%BB%93%E6%9E%84%E4%BD%93%E6%8C%87%E9%92%88" style="background-color:transparent;margin-left:.0001pt;text-align:left;">定义一个json_object结构体指针

然后要定义一个json_object结构体指针

这个结构体的原型可以在json_object_private.h这个头文件中找到

用这个结构体可以表示一个json对象。

json%E5%AF%B9%E8%B1%A1" style="background-color:transparent;margin-left:.0001pt;text-align:left;">把一个字符串转换成一个json对象

把一个字符串转换成一个json对象,我们需要用到这个函数

参数就是要转换成json对象的字符串

json%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%9C%B0%E5%9D%80%E7%BB%99%E7%BB%93%E6%9E%84%E4%BD%93%E6%8C%87%E9%92%88" style="margin-left:.0001pt;text-align:left;">将转换成json对象的字符串的地址给结构体指针

注意我们要包含一个头文件:#include <json-c/json.h>,这个头文件间接包含了其他头文件

编译的时候要加上-ljson-c,因为这个库是我们自己装的,是个外来库。

注意:如果以上编译错误就把头文件#include <json-c/json.h>改成#include <json/json.h>,另外再加上#include <stdlib.h> (int64_t这个类型编译器没有识别。这个类型在stdlib.h头文件里面有定义,所以只要在第一行,#include <stdlib.h>就行,这行代码一定要放在json.h的前面),并且编译的时候加上-ljson

接下来把json对象转换成json格式的字符串输出

用到这个函数:

参数就是Json对象

注意:此时编译运行后如果出现这个错误

就执行这些操作:

先输入命令:find /usr -name "libjson.so.0"

回车后得到一个路径,则复制路径,然后输入:cp 得到的路径   /lib

回车后再编译运行就没问题了

接下来我们来学习自己组合json格式的json对象

json%E6%A0%BC%E5%BC%8F%E7%9A%84json%E5%AF%B9%E8%B1%A1" style="background-color:transparent;margin-left:.0001pt;text-align:left;">组合json格式的json对象

json%E5%AF%B9%E8%B1%A1" style="margin-left:.0001pt;text-align:left;">第一步,创建空json对象

用到这个函数

json%E5%AF%B9%E8%B1%A1%E4%B8%AD%E5%A1%AB%E9%94%AE%E5%80%BC%E5%AF%B9" style="background-color:transparent;margin-left:.0001pt;text-align:left;">第二步,往空的json对象中填键值对

要用到这个函数

这个函数可以在json_oject.h这个头文件里找到详细解释

第一个参数是json对象,第二个参数是“键”,第三个参数是“值”。

json%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%AF%B9%E8%B1%A1" style="margin-left:.0001pt;text-align:left;">第三步,将C字符串转换成json字符串格式的对象

但是我们前面说过一个json对象可以没有键,只有值,所以一个值就是一个json对象,因此第三个参数不是直接填上字符串类型的值就行了,还得把这个值先转换成json对象,此时要用到这个函数:

然后我们继续添加键和值

json%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%AF%B9%E8%B1%A1" style="margin-left:.0001pt;text-align:left;">第四步,将整数转换成json格式的对象

如果值是int类型的数值,我们就需要用到这个函数来讲整型转换成对象

这样我们就完成了键值对的添加

最后可以打印出来看看对不对

编译运行

接下来学习解析,比如客户端通过socket将json对象发给了服务器,服务器收到这个object就要进行解析

json%E5%AF%B9%E8%B1%A1" style="background-color:transparent;margin-left:.0001pt;text-align:left;">解析json对象

我们刚刚添加的这个,里面每一对都是一个json对象

我们解析要做的事情就是把里面每一对都提取出来

比如我们根据”name”从json对象{ "name": "jack", "age": 11, "sex": "male" }中获取”jack”这个json对象,然后再将”jack”这个json对象转换成字符串输出就行了。

json%E5%AF%B9%E8%B1%A1%E8%8E%B7%E5%8F%96%E5%AF%B9%E5%BA%94%E6%95%B0%E6%8D%AE%E7%9A%84json%E5%AF%B9%E8%B1%A1" style="margin-left:.0001pt;text-align:left;">第一步,根据键名,从json对象获取对应数据的json对象

需要用到这个函数:

网上很多人会用这个函数

但是现在都推荐使用这个函数json_object_object_get_ex()

它的第一个参数是从哪个json对象里解析,第二个参数是“键”,第二个参数是存放了解析出来的Json对象的地址的指针的地址(二级指针)

但是由于虚拟机上只有json_object_object_get这个,所以这里我的代码就直接使用了json_object_object_get这个,它的第一个参数是json对象,第二个参数是键,返回值是解析出来的json对象(值)

json%E5%AF%B9%E8%B1%A1%E8%BD%AC%E5%8C%96%E4%B8%BA%E5%AF%B9%E5%BA%94%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%95%B0%E6%8D%AE" style="margin-left:.0001pt;text-align:left;">第二步,根据数据类型,将数据对应的json对象转化为对应类型的数据

要先获取对象类型

获取对象类型需要用到这个函数:

返回值是这个枚举类型:

参数是json对象

然后我们对这个函数的返回值进行判断

如果在已经知道json对象的类型,我们可以不用获取类型和判断了,直接解析和调用对应的函数打印出来就行。

运行结果:

这就是我们解析出来的json对象

接下来学习json数组

json%E6%95%B0%E7%BB%84" style="margin-left:.0001pt;text-align:left;">json数组

json%E6%95%B0%E7%BB%84%E5%AF%B9%E8%B1%A1" style="margin-left:.0001pt;text-align:left;">创建json数组对象

需要用到这个函数

往数组里面填充元素

第一个参数是刚刚创建的数组对象,第二个参数是值(要转换成对象)

json%E5%AF%B9%E8%B1%A1%E4%B8%AD" style="margin-left:.0001pt;text-align:left;">把数组对象嵌套到json对象中

数组在json对象类型中也是一个数组,所以就不需要转换了,直接把数组名(即数组的地址)传给json_object_object_add函数就可以了

运行结果

接下来就从这个obj这个对象中把数组对象中每一个元素对象解析出来

从对象中把数组对象中每一个元素对象解析出来

解析的时候我们需要用到这个函数获取Json数组的长度

参数是一个json对象

json数组对象里面的每一个元素也是一个单独的json对象,我们可以通过下标来获取这些元素对象,要用到这个函数

第一个参数是解析出来的数组对象,第二个参数是要获取的元素对象的下标

运行结果

这就是我们解析出来的数组对象里的每个元素对象

json%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93" style="margin-left:.0001pt;text-align:left;">Json-C/S架构json数据传输

接下来我们来模拟一下客户端向服务器发送json格式的数据的过程

代码演示:

这里我们要用到之前我们写的TCP服务器的代码

在客户端的代码中,在发送数据之前先搞好json对象,然后再发送给服务器

完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>//inet_addr的头文件
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>//close的头文件
#include <stdlib.h>
#include <json/json.h>int main()
{//创建socketint sockfd=socket(PF_INET,SOCK_STREAM,0);if(-1==sockfd){perror("socket");exit(1);}//发送连接请求struct sockaddr_in server_info;//保存服务器的信息bzero(&server_info,sizeof(server_info));server_info.sin_family=PF_INET;server_info.sin_port=htons(7000);server_info.sin_addr.s_addr=inet_addr("192.168.0.163");if(connect(sockfd,(struct sockaddr*)&server_info,sizeof(server_info))==-1){perror("connect");exit(2);}//发送数据//创建json对象struct json_object *json=json_object_new_object();//填充对象json_object_object_add(json,"name",json_object_new_string("jack"));//记得将json格式的字符串转成json格式的对象json_object_object_add(json,"age",json_object_new_int(11));json_object_object_add(json,"sex",json_object_new_string("male"));//发送对象//将json格式的对象转成json格式的字符串类型才能传给sendconst char*buf=json_object_to_json_string(json);if(send(sockfd,buf,strlen(buf),0)==-1)//最后一个参数写成0默认就行{perror("send");}printf("字符串%s发送成功! 长度 %ld \n",buf,strlen(buf));close(sockfd);//关闭socketreturn 0;
}

在服务器端的代码中,当收到客户端的连接请求时,接收客户端的数据,然后解析并打印输出

完整代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/socket.h>//inet_addr的头文件
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>//bzero的头文件
#include <unistd.h>
#include <stdlib.h>
#include <json/json.h>int main()
{//创建socketint sockfd=socket(PF_INET,SOCK_STREAM,0);//地址族:IPV4协议,套接字类型:流式套接字if(-1==sockfd){perror("socket");exit(1);}//绑定信息struct sockaddr_in server_info;//用于保存服务器的信息:IP,PORT,(还有个地址族)bzero(&server_info,sizeof(struct sockaddr_in));//清空server_info.sin_family=PF_INET;//地址族server_info.sin_port=htons(7000);//端口号,大于1024都行,记得转换字节序//server_info.sin_addr.s_addr=inet_addr("127.0.0.1");//这个地址每一台电脑都有回环IP地址用于测试,记得将字符串转换成长整形,并且要记得包含头文件server_info.sin_addr.s_addr=inet_addr("192.168.0.163");//对外通信if(bind(sockfd,(struct sockaddr*)&server_info,sizeof(server_info))==-1)//记得将结构体类型强转一下{perror("bind");exit(2);}//设置监听队列if(listen(sockfd,10)==-1)//队列大小填10用于测试{perror("listen");exit(3);}//程序停在这里监听......printf("等待客户端的连接...\n");//接受连接(阻塞),一旦有客户端向服务器发起连接就调用函数接收struct sockaddr_in client_info;//用于保存客户端的信息int length=sizeof(client_info);int fd=accept(sockfd,(struct sockaddr*)&client_info,(socklen_t *)&length);if(-1==fd){perror("accept");exit(4);}printf("接受客户端的连接 %d\n",fd);//连接后,服务器端要用一个buf接收数据char*buf=(char*)malloc(sizeof(char)*1024);//接受数据放在buf里面,注意,recv里面不能直接写sizeof(buf),这样buf是指针,只有四个字节,我们直接写1024int size=recv(fd,buf,1024,0);//从哪读,读到哪,读多少,属性写成0就行if(size==-1){perror("recv");exit(1);}//从客户端接受过来的是一个json格式的字符串数据,所以要解析//先将json格式的字符串转换成json格式的对象struct json_object*obj=json_tokener_parse(buf);//解析struct json_object*json;json=json_object_object_get(obj,"name");printf("name:%s\n",json_object_get_string(json));json=json_object_object_get(obj,"age");printf("age:%d\n",json_object_get_int(json));json=json_object_object_get(obj,"sex");printf("sex:%s\n",json_object_get_string(json));close(fd);//关闭TCP连接,不能再接收数据close(sockfd);//关闭socket,不能再处理客户端的请求//sockfd用于处理客户端连接 fd用于处理客户端的消息return 0;
}

运行结果:

综上,我们用json格式发送数据比用结构体要好。

下节开始学习libevent!

本篇就到这里,下篇继续!欢迎点击下方订阅本专栏↓↓↓


http://www.ppmy.cn/devtools/104648.html

相关文章

基于springboot的汽车租赁管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于springboot的汽车租赁管理系统,java…

Day-01—QT项目的新建

1.选择创建的项目类型&#xff0c;可以看到&#xff0c;这里可以创建多种语言的项目&#xff0c;可以直接用QT来进行前期C 的学习。 2.创建的名字中不要包含中文&#xff0c;可以用英文就用英文&#xff0c;如果不会英文&#xff0c;就用拼音也可以&#xff0c;保存地址中也不要…

网络安全总结①

上一篇&#xff1a;网络工程面试题② 下一篇&#xff1a;网络安全总结② 信息安全 信息安全的定义 防止任何对数 据进行未授权访问的措施 &#xff0c;或者防止造成信息有意 无意泄漏、 破坏、 丢失等 问题的发生&#xff0c; 让数据处于 远离危险、 免于威胁的状 态或特性。 …

【Java EE】深入理解 Java 线程的生命周期与状态转换

多线程编程在 Java 中是实现高效并发的核心技术之一。每个线程在其生命周期内会经历多个状态&#xff0c;这些状态反映了线程在特定时间点的行为与系统资源的使用情况。了解线程的状态及其转换机制&#xff0c;对于编写健壮的并发程序尤为重要。本文将深入探讨 Java 线程的六种…

【数据结构-前缀异或和】力扣1371. 每个元音包含偶数次的最长子字符串

给你一个字符串 s &#xff0c;请你返回满足以下条件的最长子字符串的长度&#xff1a;每个元音字母&#xff0c;即 ‘a’&#xff0c;‘e’&#xff0c;‘i’&#xff0c;‘o’&#xff0c;‘u’ &#xff0c;在子字符串中都恰好出现了偶数次。 示例 1&#xff1a; 输入&…

机器视觉-3 光学成像之明场与暗场

一. 原理介绍 在机器视觉中&#xff0c;光学成像的明场&#xff08;Bright Field&#xff09;和暗场&#xff08;Dark Field&#xff09;是两种常见的成像技术&#xff0c;分别用于不同的检测和分析场景。它们通过不同的光照方式来突出对象的特征&#xff0c;从而帮助识…

RK3568平台(UART篇)uart_driver 注册流程

一.串口子系统框架 串口子系统框架是 Linux 内核中专门用于处理串口设备的模块化框架: 在上图中,包含了多个层级,每个层级负责处理不同的功能和任务,从而实现串口设备的 完整驱动和管理。接下来依次介绍每个层级的作用。 应用层:位于最顶层,是串口子系统中用户空间应用程…

SQL 注入之 Oracle 注入

在 SQL 注入攻击的领域中&#xff0c;Oracle 数据库的注入攻击具有一定的特殊性和复杂性。Oracle 作为一种广泛使用的关系型数据库管理系统&#xff0c;其安全性一直备受关注。然而&#xff0c;由于应用程序开发中的漏洞或者不当配置&#xff0c;Oracle 数据库仍然可能成为 SQL…