网络通信序列化____json使用教程

33 篇文章 1 订阅
14 篇文章 0 订阅

网络传输中,牵扯到数据序列化,反序列化。其实,通信双方约定好序列化方式(大端/小端)即可。例如发送方按照大端序列化,接收端在接收到数据后,接收端判断自己的大小端模式,如果自己的CPU是大端模式,则不需要做大小端转换,直接进行数据解析即可。如果是小端,则解析完后还需要将数据转为小端模式。

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为对象。
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
说的再直接点,序列化的目的就是为了跨进程传递格式化数据

大端:数据高字节内容保存在内存的低地址中,数据的低字节内容保存在内存的高地址中。

小端:数据高字节内容保存在内存的高地址中,数据的低字节内容保存在内存的低地址中。

网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。 

序列化是用来通信的,服务端把数据序列化,发送到客户端,客户端把接收到的数据反序列化后对数据进行操作,完成后再序列化发送到服务端,服务端再反序列化数据后对数据进行操作。说白了,数据需要序列化以后才能在服务端和客户端之间传输。这个服务端和客户端的概念是广义的,可以在网络上,也可以在同一台机器的不同进程中,甚至在同一个进程中进行通信。在传统编程中,对象是通过调用栈间接的与客户端交互,但在面向服务的编程中,客户端永远都不会直接调用实例。

不同的CPU有不同的字节序类型,这些字节序是指 整数 在内存中保存的顺序,这个叫做 主机序。

最常见的有两种:

1.Little endian:将低序字节存储在起始地址

2.Big endian:将高序字节存储在起始地址

LE little-endian(小端)

  • 最符合人的思维的字节序;
  • 地址低位存储值的低位;
  • 地址高位存储值的高位;
  • 怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说; 
  • 低位值小,就应该放在内存地址小的地方,也即内存地址低位;
  • 反之,高位值就应该放在内存地址大的地方,也即内存地址高位;

BE big-endian(大端)

  • 最直观的字节序;
  • 地址低位存储值的高位; 
  • 地址高位存储值的低位;
  • 为什么说直观,不要考虑对应关系; 
  • 只需要把内存地址从左到右按照由低到高的顺序写出;
  • 把值按照通常的高位到低位的顺序写出;
  • 两者对照,一个字节一个字节的填充进去;

x86系列CPU都是little-endian的字节序。

网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。

为了进行转换 bsd socket提供了转换的函数 有下面四个

htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序

在使用little endian的系统中,这些函数会把字节序进行转换;

在使用big endian类型的系统中,这些函数会定义成空宏;

同样,在网络程序开发时 或是跨平台开发时,也应该注意保证只用一种字节序,不然两方的解释不一样就会产生bug。

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

JSON有两种表示结构,对象和数组。
对象结构以”{”大括号开始,以”}”大括号结束。中间部分由0或多个以”,”分隔的”key(关键字)/value(值)”对构成,关键字和值之间以”:”分隔,语法结构如代码。

{
    key1:value1,
    key2:value2,
    ...
}

其中关键字是字符串,而值可以是字符串,数值,true,false,null,对象或数组

数组结构以”[”开始,”]”结束。中间由0或多个以”,”分隔的值列表组成,语法结构如代码。

[
    {
        key1:value1,
        key2:value2 
    },
    {
         key3:value3,
         key4:value4   
    }
]

 

认识JSON字符串

普通字符串,json字符串和json对象的区别:

字符串:这个很好解释,指使用“”双引号或’’单引号包括的字符。例如:var comStr = 'this is string';
json字符串:指的是符合json格式要求的js字符串。例如:var jsonStr = "{StudentID:'100',Name:'tmac',Hometown:'usa'}";
json对象:指符合json格式要求的js对象。例如:var jsonObj = { StudentID: "100", Name: "tmac", Hometown: "usa" };

c++中使用json

服务器端:

/*************************************************************************
	> File Name: service.cpp
	> Author: 计献之 
	> Mail: 1841531744@qq.com 
	> Created Time: 2018年11月22日 星期四 12时20分37秒
 ************************************************************************/

#include<iostream>
using namespace std;

#include<iostream>
#include<string.h>
#include<string>
#include<arpa/inet.h>
#include<errno.h>
#include<json/json.h>
#include<sys/socket.h>
using namespace std;
//服务器端程序
int main()
{
    //创建服务器
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == fd)
    {
        cerr<<"fd creat fail;errno:"<<endl;
        return 0;
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(5000);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    //绑定
    if(-1 == bind(fd,(struct sockaddr*)&addr,sizeof(addr)))
    {
        cerr<<"fd bind fail;errno:"<<errno<<endl;
        return 0;
    }

    cout <<"监听"<<endl;
    //监听
    if(-1 == listen(fd,20))
    {
        cerr<<"fd listen fail;errno:"<<endl;
        return 0;
    }
    //连接客户端
    struct sockaddr_in caddr;
    socklen_t len = sizeof(caddr);
    int clifd = accept(fd,(struct sockaddr*)&caddr,&len);
    if(-1 == clifd)
    {
        cerr<<"accept client fail;errno:"<<errno<<endl;
        return 0;
    }
    //接收消息
    char buff[100] = {0};
    if(0 < recv(clifd,buff,99,0))
    {
        cout<<buff<<endl;
    }
    //解析json
    Json::Value val;
    Json::Reader read;
    if(-1 == read.parse(buff,val))
    {
        cerr<<"read fail;errno:"<<errno<<endl;
        return 0;
    }
    //cout<<val.asString()<<endl;
    cout<<"name:"<<val["name"].asString()<<endl;
    cout<<"pw:"<<val["pw"].asString()<<endl;
    //发送消息
    Json::Value root;
    root["reason"] = "ok";
    if(-1 == send(clifd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
    {
        cerr<<"send reason fail;errno:"<<errno<<endl;
        return 0;
    }
    return 0;
}

客户端:

/*************************************************************************
	> File Name: client.cpp
	> Author: 计献之 
	> Mail: 1841531744@qq.com 
	> Created Time: 2018年11月22日 星期四 12时05分17秒
 ************************************************************************/

#include<iostream>
#include<string.h>
#include<string>
#include<json/json.h>
#include<json/value.h>
#include<json/autolink.h>
#include<json/config.h>
#include<json/features.h>
#include<json/forwards.h>
#include<json/reader.h>
#include<json/writer.h>
#include<errno.h>
#include<arpa/inet.h>
using namespace std;

//客户端程序
int main()
{
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == fd)
    {
        cerr<<"clifd creat fail;errnoz:"<<errno<<endl;
        return 0;
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(5000);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    if(-1 == connect(fd,(struct sockaddr*)&addr,sizeof(addr)))
    {
        cerr<<"clifd connect fail;errno:"<<errno<<endl;
        return 0;
    }
//创建json包
    Json::Value val;
    val["name"] = "zhangsan";
    val["pw"] = "123456";
//发送数据
    if(-1 == send(fd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0))
    {
        cerr<<"send reason fail;errno:"<<errno<<endl;
        return 0;
    }
    char buff[100] = {0};
//接收数据
    if(0 < recv(fd,buff,99,0))
    {
        //解析json包
        Json::Value root;
        Json::Reader read;
        if(-1 == read.parse(buff,root))
        {
            cerr<<"json prase fail;errno:"<<errno<<endl;
            return 0;
        }
        //输出json
        //cout<<root.asString()<<endl;
        cout<<"reason:"<<root["reason"].asString()<<endl;
    }
    return 0;
}

编译链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值