浅谈jsoncpp及实现服务器客户端之间json包传输

JSON是什么?

JSON 是一种用于数据交换的文本格式(本质是一种文件组织方式,比如你熟悉的txt, csv, doc,docx文件等等),目的是取代繁琐笨重的XML格式。这种格式不仅人很容易进行阅读和编写,同时机器也很容易解析和生成,是当前十分流行的数据格式,尤其是在前端领域。JSON是一种传递对象的语法,对象可以是name/value对、数组其他对象,现在浏览器都自带json解析。

简单来说json就是一种客户端与服务器都可以识别及解析的数据格式,避免了难以定义数据格式的麻烦。比如:如果你每个客户端想给服务器一次发送名称,年龄,密码等信息,那么服务器用什么数据结构来接收呢?有人就说用结构体,但是结构体中各个变量我们定义多大呢?是吧,多大都不合适,所以有了json这种统一的数据格式,双方都根据json的规则进行解析就可以获取到双方发送的字节流(网络中用字节流传输),而不必为定义每个数据的大小而苦恼(相当于发送接收都是一个json对象不存在大小不一致)。可以将json理解为一个容器,我们按照容器的打开方式就可以打开容器获取到数据。

举个栗子(下面提供一小段json代码)? 

{
    "firstname":"John",
    "lastname":"smith",
    "isAlive":true,
    "age":25,
    "address":{
     "streetaddress":"21 street",   //街道地址
     "city":"XI'AN",       //城市地址
    },
    "phonenum":{
    {
        "type":"home",  //家庭电话
        "number": "212555666" 
    },
    {
        "type":"office",  //公司电话
        "number":"645111999"
    }      
    },
    "children":{
    [{"name":"mary","age",2},{"name":"bob","age":4}]  //数组
    },
    "spouse":null
}

这是个json,存储的数据描述了一个人John Smith的一些个人信息,比如姓名,是否活着,年龄,地址以及电话号码等信息。其中,地址address和电话号码phonenum呢,下面又包含了街道、城市,家庭电话、办公电话信息。

如果之前只接触过存储在Excel或者sql server等结构化数据库中的结构化数据,那么第一次看到json格式的数据,一定觉得很新颖。这种数据组织方式,条理清晰,能更好的表示自然界中人或物等实体的属性关系。可以理解为一种树状结构,一棵有枝干,枝干上有叶子的树。

你看懂了吧?那么当你再看到它时就知道它是JSON了。主要部分:

花括弧,方括号,冒号和逗号

  • 花括弧表示一个“容器”
  • 方括号装载数组
  • 名称和值用冒号隔开
  • 数组元素通过逗号隔开

区分json和XML?

<1>什么是XML?

XML也是一种格式规范,是一种包含了数据以及数据说明的文本格式规范,它是可扩展标记语言。扩展标记语言不是超文本标记语言(eg:HTML)的替代而是对超文本标记语言的补充。XML不像HTML这种超文本标记语言用于网页的编辑(被设计用来显示数据,其焦点是数据的外观),它主要用于数据格式化存储(被设计用来传输和存储数据,其焦点是数据的内容),现在用的比较多的是作为配置文件(表述底层数据)或者数据结构定义(数据载体),在网络中传输,是网络传输中间语言。

举个栗子说明一下:

比如,我们要给对方传输一段数据,数据内容是“too young,too simple,sometimes naive”,要将这段话按照属性拆分为三个数据的话,就是,年龄too young,阅历too simple,结果sometimes naive。

我们都知道程序不像人,可以体会字面意思,并自动拆分出数据,因此,我们需要帮助程序做拆分,因此出现了各种各样的数据格式以及拆分方式。

比如,可以是这样的
数据为“too young,too simple,sometimes naive”
然后按照逗号拆分,第一部分为年龄,第二部分为阅历,第三部分为结果。

这种方式可以用来容纳数据并能够被解析,但是不直观,通用性也不好。基于这种情况,出现了xml这种数据格式, 上面的数据用XML表示的话
可以是这样

<person age="too young" experience="too simple" result="sometimes naive" />

也可以是这样

<person>
    <age value="too young" />
    <experience value="too simple" />
    <result value="sometimes naive" />
</person>

两种方式都是xml,都很直观,附带了对数据的说明,并且具备通用的格式规范可以让程序做解析。

与普通的纯文本保存数据不同的是XML与json做了数据的拆分和归类,以便让计算程序区分各部分的内容

拆分方式有多种,可以这样来表述:

  • 用XML格式拆分数据
  • 用JSON格式拆分数据

xml可用于存储,传输,交换数据,因为只描述/关心数据的结构,可以做到平台无关,实现跨平台,所以Windows平台喜欢,Linux平台喜欢,各种系统(包括非操作系统)都喜欢用它,它可拓展性好,对人类友好,结构清晰易读。

小知识:

记得好像据说,最早是在万维网刚出现的时候,为了在万维网上传输数据,接收方能造理解,人们创了这种自带格式说明的文件格式。当时人们期待着xml能一统天下,结果后来html和浏览器出现了,html成了标准的网络协议,就没xml什么事了。现在xml就是个工具,干啥都行。可以存储并检索数据,可以做传输约定格式,可以做配置文件。

<2>json与xml的相同点及json比xml好在哪里?

首先XML和JSON都使用结构化方法来标记数据,而且它们的值都是可列举的,是“人类可读”的,两者都可以嵌套(有层级的,可以在值里再存放值)),而且都能被多种的编程语言解析和使用,都能使用AJAX方法来传递(例如httpWebRequest) 。

但是JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多(相比 XML 文件更小,相比XML确实更加轻量级,可以大大得节约传输数据所占用得带宽。XML有时候描述东西太费劲,验证复杂,而且有大量的冗余,尤其是结束标记(</html>)。如果只是几个元素没什么,如果非常多,就不利于网络传输了,所以现在网络上用的非常多的是JSON。但是XML作为半结构化文档的代表性标准,早期代表的是一种数据思想。另外JSON的结构更容易映射至一般语言的数据结构,而且json具有长时间的稳定性(JSON 格式的创始人声称此格式永远不升级),并且javaScript天生支持Json,解析一点都不费劲

XML相比JSON最大的区别是充满了冗余信息。多数时候我们不需要冗余信息,但是一旦需要的时候没有就是不行。这就是XML与JSON最大的区别。为什么很多人都说json比较好,因为多数时候不需要冗余信息。

<3>为啥有了json还需要使用xml?

我们在选择用哪种方式存储数据一般会考虑以下两点

  • 哪种更容易阅读
  • 哪种更容易被程序解析(正反序列化)

根据不同的需求我们才会选择存储方式,只是json比较简单,容易阅读而已,但是在某些场合,在人机都需要识别数据的时候,比如配置文件,选择xml正是因为有大量的冗余(提示信息)使得xml的可读性比json好。所以说我们选择那种方式取决于我们的需求,这两者不是互相替代的

看个XML和json的栗子

XML:

<?xml version="1.0" encoding="utf-8">
<country>
    <name>中国</name>
    <province>
        <name>广东</name>
        <cities>
            <city>广州</city>
            <city>佛山</city>
            <city>深圳</city>
        </cities>
    </province>
    <province>
        <name>陕西</name>
        <cities>
            <city>西安</city>
            <city>渭南</city>
            <city>咸阳</city>
        </cities>
    </province>
</country>

json:

{
    "name":"中国",
    "province":[
     {
        "name":"广东",
        "cities":
         {
            "city":["广州","佛山","深圳"]
         }
     }, 
     {    
        "name":"陕西",
        "cities":
          {
             "city":["西安","渭南","咸阳"]
          }
     }]   
}

看出来没,其实数据都是一样的,不同的只是数据的格式而已,同样的数据,我用xml格式传给你,你用xml格式解析出数据,用json格式传给你,你就用json格式解析出数据,还可以我本地保存的是xml格式的数据,我自己先解析出数据,然后构造成json格式传给你,你解析json格式,获得数据,再自己构造成xml格式保存起来,说白了,不管是xml还是json,都只是包装数据的不同格式而已,重要的是其中含有的数据,而不是包装的格式。

json用法:

关于json用法大家可以参考这两个博客:

jsoncpp用法详解             阮一峰老师的json对象

客户端与服务器之间json包传输简单示例代码

服务器:

#include<iostream>
#include<string.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<errno.h>
#include<json/json.h>
#include<sys/types.h>
#include<sys/socket.h>
//json链接的时候要加上 -ljson库
using namespace std;
int main()
{
	int sockfd=socket(AF_INET,SOCK_STREAM,0);
	if(sockfd==-1)
	{
		cout<<"socket fail;errno:"<<errno<<endl;
		return 0;
	}
	struct sockaddr_in ser,cli;
	ser.sin_family=AF_INET;
	ser.sin_port=htons(5500);
	ser.sin_addr.s_addr=inet_addr("127.0.0.1");
	if(-1==bind(sockfd,(struct sockaddr*)&ser,sizeof(ser)))
	{
		cerr<<"bind fail;errno:"<<errno<<endl; //cerr
		return 0;
	}
	if(-1==listen(sockfd,20))
	{
		cout<<"listen fail;errno:"<<errno<<endl;
		return 0;
	}
	socklen_t len=sizeof(cli);
	int clifd=accept(sockfd,(struct sockaddr*)&cli,&len);
	if(-1==clifd)
	{
		cout<<"accept fail;errno:"<<errno<<endl;
		return 0;
	}
	char buff[128]={0};
	int n=recv(clifd,buff,127,0);//从网络中读取到字符流
	if(n>0)
	{
		//解析客户端发送的json包,json包含三种类型的类:Value  Reader Writer
		Json::Value val; //Value是jsoncpp中最基本及重要的类,表示各种类型的对象,val是定义了临时对象,供下面代码用
		Json::Reader read;//用于读取,将字符串转化为Json::Value对象
		if(-1==read.parse(buff,val)) //将buff转化为Json::Value对象
		{
			cout<<"change json fail;errno:"<<errno<<endl;
			return 0;
		}
		cout<<val.toStyledString()<<endl;
		//cout<<"name:"<<val["name"].asString()<<endl; //asString将远程的结果转化为字符串
		//cout<<"pw:"<<val["pw"].asString()<<endl;

		//给客户端发送消息
		Json::Value root;  //root表示整个json对象
		root["reason"]="ok";  //新建一个key(名为reason)赋予字符串值ok
		if(-1==send(clifd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0)) //将json对象转化为字符串在网络中传输
		{
			cout<<"send reason fail;errno:"<<errno<<endl;
			return 0;
		}
	}
	else
	{
		cout<<"recv fail;errno:"<<errno<<endl;
		return 0;
	}
	return 0;
}

客户端: 

#include<iostream>
#include<string.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<errno.h>
#include<json/json.h>
#include<sys/types.h>
#include<sys/socket.h>
using namespace std;
int main()
{
	int sockfd=socket(AF_INET,SOCK_STREAM,0);
	if(sockfd==-1)
	{
		cout<<"socket fail;errno:"<<errno<<endl;
		return 0;
	}
	struct sockaddr_in ser,cli;
	ser.sin_family=AF_INET;
	ser.sin_port=htons(5500);
	ser.sin_addr.s_addr=inet_addr("127.0.0.1");
	if(-1==connect(sockfd,(struct sockaddr*)&ser,sizeof(ser)))
	{
		cout<<"clifd connect fail;errno:"<<errno<<endl;
		return 0;
	}

	//创建json包
	Json::Value val;
	val["name"]="zhangsan";//新建key为name 值为zhangsan的val对象中的一个映射
	val["pw"]="123456";
	//发送数据
	if(-1==send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0))
	{
		cout<<"clifd send fail;errno:"<<errno<<endl;
		return 0;
	}
	//接受数据
	char buff[128]={0};
	if(recv(sockfd,buff,127,0)<=0)
	{
		cout<<"clifd recv fail;errno:"<<errno<<endl;
		return 0;
	}
	Json::Value root;
	Json::Reader read;
	if(-1==read.parse(buff,root))  //字符串转化为json对象
	{
		cout<<"json parse fail;errno:"<<errno<<endl;
		return 0;
	}
	//输出json
	//cout<<root.asString()<<endl; 
	cout<<"reason:"<<root["reason"].asString()<<endl; //按字符串打印
	return 0;
}

编译链接时需要加上json库

运行结果:

服务器输出时还有一种将数据分开的方式,我上面引起来了,大家可以自己放开测试一下。 

猜你喜欢

转载自blog.csdn.net/Eunice_fan1207/article/details/84443265