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

news2024/11/13 15:25:23

目录

入门级问题

为什么使用json?

什么是json?

json-c库

json源码

安装方法

json-c API

Json类型

C-API

将一个字符串转换成符合json格式的字符串(json对象)

定义一个字符串数组

定义一个json_object结构体指针

把一个字符串转换成一个json对象

将转换成json对象的字符串的地址给结构体指针

组合json格式的json对象

第一步,创建空json对象

第二步,往空的json对象中填键值对

第三步,将C字符串转换成json字符串格式的对象

第四步,将整数转换成json格式的对象

解析json对象

第一步,根据键名,从json对象获取对应数据的json对象

第二步,根据数据类型,将数据对应的json对象转化为对应类型的数据

json数组

创建json数组对象

往数组里面填充元素

把数组对象嵌套到json对象中

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

Json-C/S架构json数据传输


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

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

入门级问题

为什么使用json?

以QQ注册的场景为例。

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

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

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

什么是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库

json支持很多种语言

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

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

json源码

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

提取码:asn5

安装方法

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

./autogen.sh

./configure

make

make install

json-c API

Json类型

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

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

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

比如这就是一个object类型,

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

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

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

还有array数组类型

比如

C-API

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

将一个字符串转换成符合json格式的字符串(json对象)

定义一个字符串数组

先定义一个字符串数组

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

定义一个json_object结构体指针

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

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

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

把一个字符串转换成一个json对象

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

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

将转换成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格式的json对象

第一步,创建空json对象

用到这个函数

第二步,往空的json对象中填键值对

要用到这个函数

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

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

第三步,将C字符串转换成json字符串格式的对象

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

然后我们继续添加键和值

第四步,将整数转换成json格式的对象

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

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

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

编译运行

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

解析json对象

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

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

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

第一步,根据键名,从json对象获取对应数据的json对象

需要用到这个函数:

网上很多人会用这个函数

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

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

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

第二步,根据数据类型,将数据对应的json对象转化为对应类型的数据

要先获取对象类型

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

返回值是这个枚举类型:

参数是json对象

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

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

运行结果:

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

接下来学习json数组

json数组

创建json数组对象

需要用到这个函数

往数组里面填充元素

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

把数组对象嵌套到json对象中

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

运行结果

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

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

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

参数是一个json对象

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

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

运行结果

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

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()
{
	//创建socket
	int 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格式的字符串类型才能传给send
	const 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);//关闭socket

	return 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()
{
	//创建socket
	int 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是指针,只有四个字节,我们直接写1024
	int 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.coloradmin.cn/o/2095360.html

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

相关文章

TS类型注解(下)

文章目录 前言三、TypeScript类型约束&#xff08;5&#xff09;对象&#xff08;6&#xff09;接口&#xff08;TS中对象类型的专属约束&#xff09;&#xff08;7&#xff09;TS中的扩展类型 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&…

台式机CPU温度90℃以上-排查思路

虽然现在台式机不值钱。 但是对于穷苦老百姓来说&#xff0c;还是害怕它坏掉&#xff0c;坏掉就又需要花钱买了。 ①风扇清理所有灰尘&#xff08;风扇的散热网是可以拆下来的&#xff09;&#xff0c; 主板清理所有灰尘&#xff08;用画笔或者干燥的牙刷&#xff0c;注意是…

LeetCode - 11 盛最多水的容器

题目来源 11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最…

小型集群分析

目录 介绍步骤 介绍 etcd是CoreOS基于Raft协议开发的分布式key-value存储&#xff0c;可用于服务发现、共享配置以及一致性保障&#xff08;如数据库选主、分布式锁等&#xff09;。 在分布式系统中&#xff0c;如何管理节点间的状态一直是一个难题&#xff0c;etcd像是专门为…

从关键新闻和最新技术看AI行业发展(第三十期2024.8.12-8.25) |【WeThinkIn老实人报】

写在前面 【WeThinkIn老实人报】旨在整理&挖掘AI行业的关键新闻和最新技术&#xff0c;同时Rocky会对这些关键信息进行解读&#xff0c;力求让读者们能从容跟随AI科技潮流。也欢迎大家提出宝贵的优化建议&#xff0c;一起交流学习&#x1f4aa; 欢迎大家关注Rocky的公众号&…

java利用JXL操作excel

通过JXL操作Excel JXL是韩国人所著,目前停止更新,只支持xls格式,即2007之前的版本 import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java…

【论文解读】SAM模型超级进化:面向移动端的轻量级SAM,比FastSAM快4倍!(附论文地址)

论文地址&#xff1a;https://arxiv.org/pdf/2306.14289.pdf 这篇论文的标题是《FASTER SEGMENT ANYTHING: TOWARDS LIGHTWEIGHT SAM FOR MOBILE APPLICATIONS》&#xff0c;由Chaoning Zhang等人撰写&#xff0c;发表于2023年。 文章主要探讨了如何将Segment Anything Model&…

Docker构建镜像时本地NuGet不存在的解决方式

在打包镜像时&#xff0c;由于程序中使用了本地的NuGet包&#xff0c;发现怎么打包都是失败,错误如下 我的dockerfile 文件如下 FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 80# 此阶段用于生成服务项目 FROM mcr.microsoft.com/dotnet/sdk:8.0 A…

战略设计(Strategic Design)

战略设计(strategic design)——一种针对系统整体的建模和设计决策。这样的决策影响整个项目&#xff0c;而且必须由团队来制定。 随着系统的增长&#xff0c;它会变得越来越复杂&#xff0c;当我们无法通过分析对象来理解系统的时候&#xff0c;就需要掌握一些操纵和理解大的模…

Docker简介及部署方法

什么是 docker &#xff1f; Docker是一个开源的应用容器引擎&#xff0c;它允许开发者将应用及其依赖打包到一个轻量级、可移植的容器中&#xff0c;并几乎可以在任何支持的平台上运行。Docker利用Linux内核的功能&#xff08;如Cgroups和namespaces&#xff09;来实现对进程的…

《JavaEE进阶》----7.<SpringMVC实践项目:【登录页面的验证】>

这篇文章详细的讲解了一个 简单的登录网页的前端代码和后端代码的构造 使用了JavaScript中的ajax来进行前后端的交互 一、前端代码 登录页面代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>登录…

从0开始深度学习(2)——自动微分

1 微积分 1.1 导数和微分 略 1.2 偏导数 略 1.3 梯度&#xff08;gradient&#xff09; 1.3.1 定义 对于一个多变量函数 f ( x 1 , x 2 , … , x n ) f\left(x_{1}, x_{2}, \ldots, x_{n}\right) f(x1​,x2​,…,xn​)其中点 a ( a 1 , a 2 , … , a n ) \mathbf{a}(a_…

【栈经典问题剖析】上

1.1进制转换 1.1.2思路图解&#xff1a; 每次将得到的余数存入栈中&#xff0c;直到商为0时&#xff0c;停止入栈。依次将栈中元素出栈并进行打印操作&#xff08;注意负数的符号情况&#xff09; //进制转换&#xff1a;10进制整数转换成8进制整数 #include <stdio.h>…

Google的MapReduce和Hadoop的MapReduce基本原理

Google的MapReduce和Hadoop的MapReduce基本原理 MapReduce框架的执行过程可以概述为以下几个关键步骤&#xff1a; 输入分割&#xff1a;用户程序中的MapReduce库首先将输入文件分割成M个片段&#xff0c;每个片段通常大小在16MB到64MB之间&#xff0c;用户可以通过可选参数控制…

【leetcode413周赛】——前两题python

3274. 检查棋盘方格颜色是否相同 给你两个字符串 coordinate1 和 coordinate2&#xff0c;代表 8 x 8 国际象棋棋盘上的两个方格的坐标。 以下是棋盘的参考图。 如果这两个方格颜色相同&#xff0c;返回 true&#xff0c;否则返回 false。 坐标总是表示有效的棋盘方格。坐标…

【indirect 函数 ★二级下拉菜单】

Indirect 函数 &#x1f33c;indirect函数参数&#x1f33c;应用&#xff1a;&#x1f33c;跨表引用同一单元格&#x1f33c;二级下拉列表 &#x1f33c;indirect函数参数 返回⬅️【文本字符串所指定的引用】 INDIRECT(ref_text,[a1]) 其中【ref_text】是引用的文本 [a1] 是…

大数据之数据湖Apache Hudi

一、Hudi框架概述 Apahe Hudi (Hadoop Upserts delete and Incrementals) 是Uber主导开发的开源数据湖框架&#xff0c;为了解决大数据生态系统中需要插入更新及增量消费原语的摄取管道和ETL管道的低效问题&#xff0c;该项目在2016年开始开发&#xff0c;并于2017年开源&#…

Mysql基础练习题 1084.销售分析3 (力扣)

编写解决方案&#xff0c;报告 2019年春季 才售出的产品。即 仅 在 2019-01-01 &#xff08;含&#xff09;至 2019-03-31 &#xff08;含&#xff09;之间出售的商品 题目链接&#xff1a; https://leetcode.cn/problems/sales-analysis-iii/description/ 建表插入数据&…

学习指纹浏览器 处理美团mtgsig1.2 环境检测

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我…

恭喜各位天命人!2024年国自然基金放榜了!优青654项、杰青433项,附个人查询攻略

公众号&#xff1a;生信漫谈&#xff0c;获取最新科研信息&#xff01; 恭喜各位天命人&#xff01;2024年国自然基金放榜了&#xff01;优青654项、杰青433项&#xff0c;附个人查询攻略https://mp.weixin.qq.com/s?__bizMzkwNjQyNTUwMw&mid2247487048&idx1&sn1…