http协议(序列化与反序列化)

目录

1.序列化与反序列化的过程

2.序列化的原因

3.json实现序列化

3.1 安装json

3.2 json的使用

3.2.1 序列化使用

3.2.2  反序列化的过程

4.实现网络版本的计算器

4.1 指定协议与序列化反序列化

4.2 基本网络通信(采用TCP协议)

4.3 通信具体业务

4.3.1 服务端

4.3.2 客户端

5 总结


1.序列化与反序列化的过程

如果客户端的数据是一个结构体,这个结构体要发送给服务端。网络传输的过程中需要将这个结构体转化成字符串,这个过程称为序列化。而数据由字符串转化成结构体再被服务端接收的过程,称为反序列化过程。

结构化的过程其实就是协议的一种体现

2.序列化的原因

1.结构化的数据不利于网络的传输(为了应用层网络通信的方便)

2.为了方便上层使用内部成员,将应用层和网络进行解耦。

我们之前做的tcp和UDP通信没有做任何序列化和反序列化。可以json等组件来实现序列化和反序列化。

3.json实现序列化

3.1 安装json

yum install -y jsoncpp -devel

安装后我们可以再/usr/include/jsoncpp/json找到安装的头文件。

json是一款实现序列化和反序列化的组件。假设我们要实现一个网络版的计算器,客户端发送与服务端发送的结构体如下:

#include <iostream>
using namespace std;
typedef struct request
{
    int x;
    int y;
    char op;
} request_t;
typedef struct response
{
    int code; // code(0)表示成功,code(-1)表示除以0,code(-2)表示对0取模
    int result;
} response_t;

3.2 json的使用

3.2.1 序列化使用

1.首先建立Value对象,使用其来接收结构体中的值。

2.使用Write对象的write方法,将root对象写入字符串中,即可形成一个序列化的字符串。形成的序列化字符串有我们新增的key的内容,在反序列化的时候可以拿掉。

request_t req={10,20,'*'};
Json::Value root;//可以承载任何对象,json是一种KV式序列化方案
root["datax"]=req.x;
root["datay"]=req.y;
root["operator"]=req.op;
Json::StyledWriter writer;
string json_string=writer.write(root);
cout<<json_string<<endl;

拿到的字符串是:

3.2.2  反序列化的过程

1.首先建立Value对象与Reader对象。

2.使用Reader对象的parse方法,将Value对象与字符串相关联。

3.使用Value对象的KV结构来对结构体赋值。

    string json_string=R"({"datax":10,"datay":20,"operator":42})";
    cout<<json_string<<endl;
    Json::Value root;
    Json::Reader reader;
    reader.parse(json_string,root);//将root对象与要反序列化的字符串关联
    request_t req;
    req.x=root["datax"].asInt();
    req.y=root["datay"].asInt();
    req.op=(char)root["operator"].asInt();
    cout<<req.x<<req.y<<req.op<<endl;

4.实现网络版本的计算器

4.1 指定协议与序列化反序列化

制定协议的过程,其实就是规定服务端与客户端的结构化数据的结构是什么,比如,我们规定客户端发送的数据的格式和服务端接收数据的格式:

#include <iostream>
#include <jsoncpp/json/json.h>

using namespace std;
typedef struct request
{
    int x;
    int y;
    char op;
}request_t;

typedef struct response
{
    int code; //code(0)表示成功,code(-1)表示除以0,code(-2)表示对0取模
    int result;
} response_t;

string SerializeRequest(const request_t& req)
{
    Json::Value root;
    Json::FastWriter writer;
    root["datax"]=req.x;
    root["datay"]=req.y;
    root["operator"]=req.op;
    string json_string=writer.write(root);
    return json_string;
}

void DeserializeRequest(string& json,request_t& out)
{
    Json::Value root;
    Json::Reader reader;
    out.x=root["datax"].asInt();
    out.y=root["datay"].asInt();
    out.op=(char)root["operator"].asInt();
}
string SerializeResponse(const response& res)
{
    Json::Value root;
    Json::FastWriter writer;
    root["code"]=res.code;
    root["result"]=res.result;
    string json_string=writer.write(root);
    return json_string;
}
void DeserializeResponse(string& json,response_t& out)
{
    Json::Value root;
    Json::Reader reader;
    reader.parse(json,root);
    out.code=root["code"].asInt();
    out.result=root["result"].asInt();
}

4.2 基本网络通信(采用TCP协议)

#include <iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>
using namespace std;
namespace ns_Sock
{
    class Sock
    {
    private:
    public:
        static int Socket()
        {
            int sock = socket(AF_INET, SOCK_STREAM, 0);
            if (sock < 0)
            {
                cerr << "创建套接字失败" << endl;
                exit(-2);
            }
            else
            {
                return sock;
            }
        }
        static int Listen(int sock)
        {
            if(listen(sock,5)<0)
            {
                cerr<<"listen error"<<endl;
                exit(-3);
            }
        }
        static int Accept(int sock)
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int fd=accept(sock,(struct sockaddr*)&peer,&len);
            if(fd>=0)
            {
                return fd;
            }
            else
            {
                exit(-5);
            }
        }
        static void Bind(int sock,uint16_t port)
        {
            sockaddr_in local;
            local.sin_family=AF_INET;
            local.sin_port=htons(port);
            local.sin_addr.s_addr=INADDR_ANY;
            if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
            {
                cerr<<"bind error"<<endl;
                exit(-4);
            }
        }
        static void Connect(int sock,string ip,uint16_t port)
        {
            struct sockaddr_in server;
            memset(&server,0,sizeof(server));
            server.sin_family=AF_INET;
            server.sin_port=htons(port);
            server.sin_addr.s_addr=inet_addr(ip.c_str());
            if(connect(sock,(struct sockaddr*)&server,sizeof(server))==0)
            {
                cout<<"connect success!"<<endl;
            }
            else
            {
                cout<<"connect fail"<<endl;
                exit(-5);
            }
        }

    };
}

4.3 通信具体业务

4.3.1 服务端
#include "protonol.hpp"
#include "Sock.hpp"
using namespace ns_Sock;
using namespace std;
void Usage(string proc)
{
  cout << proc << " port" << endl;
}
void *HandlerRequest(void *args)
{
  int sock = *(int *)args;
  delete (int *)args;
  pthread_detach(pthread_self());
  char buffer[1024];
  ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
  request_t req;
  response_t res = {0, 0};
  buffer[s] = 0;
  string str = buffer;
  cout << str << endl;
  DeserializeRequest(str, req);
  switch (req.op)
  {
  case '+':
    res.result = req.x + req.y;
    break;
  case '-':
    res.result = req.x - req.y;
    break;
  case '*':
    res.result = req.x * req.y;
    break;
  case '/':
    if (req.y == 0)
      res.code = -1;
    else
      res.result = req.x / req.y;
    break;
  case '%':
    if (req.y == 0)
      res.code = -2;
    else
      res.result = req.x % req.y;
    break;
  default:
    res.code = -3;
  }
  cout << "code=" << res.code << endl;
  cout << req.x << req.op << req.y << "=" << res.result << endl;
  string json_string = SerializeResponse(res);
  write(sock, json_string.c_str(), json_string.size());
  cout << "send an answer" << json_string;
  // write(sock,&res,sizeof(res));
}

int main(int argc, char *argv[])
{
  if (argc != 2)
  {
    Usage(argv[0]);
    return -1;
  }
  uint16_t port = atoi(argv[1]);
  int listen_sock = Sock::Socket();
  Sock::Bind(listen_sock, port);
  Sock::Listen(listen_sock);
  while (true)
  {
    int sock = Sock::Accept(listen_sock);
    if (sock > 0)
    {
      cout << "get a new link..." << endl;
      int *pram = new int(sock);
      pthread_t tid;
      pthread_create(&tid, nullptr, HandlerRequest, pram);
    }
  }
}
4.3.2 客户端
#include"Sock.hpp"
#include"protonol.hpp"
using namespace std;
using namespace ns_Sock;
void Usage(string proc)
{
    cout<<proc<<" ip"<<" port"<<endl;
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        return -1;
    }
    int sock=Sock::Socket();
    Sock::Connect(sock,argv[1],atoi(argv[2]));
    request_t req;
    memset(&req,0,sizeof(req));
    cout<<"Please Enter Data1:#";
    cin>>req.x;
    cout<<"Please Enter Data2:#";
    cin>>req.y;
    cout<<"Please Enter op:#";
    cin>>req.op;
    string json_string=SerializeRequest(req);
    cout<<json_string<<endl;
    write(sock,json_string.c_str(),json_string.size());
    response_t res;
    char buffer[1024];
    memset(buffer,0,sizeof(buffer));
    ssize_t s=read(sock,&buffer,sizeof(buffer)-1);
    buffer[s]=0;
    string str=buffer;
    cout<<str<<endl;
    DeserializeResponse(str,res);
    cout<<"code[0:-3]#"<<res.code<<endl;
    cout<<"result#"<<res.result<<endl;
}
}

5 总结

我们可以将上面的代码分为三部分,分别是基本通信代码(会话层),序列化反序列化代码(表示层),约定以及业务逻辑代码(应用层)。这些在TCP/IP四层协议中统称为应用层。http协议是应用层协议,因此需要完成以上三个工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值