应用层协议 序列化

自定义应用层协议

例子:网络版本计算器

序列化反序列化

序列化:将消息,昵称,日期整合成消息-昵称-日期

反序列化:消息-昵称-日期->消息,昵称,日期

在序列化中,定义一个结构体

cpp 复制代码
                struct Message{
	  		 	string message;
				string name;
				string data;};

用这个结构体进行通信,就是一种协议,约定好的一种结构化字段就叫做协议

再比如

cpp 复制代码
 struct complate{
 int num1;
 int num2;
 char  oper;
}

序列化:将协议规定的结构化数据转换成字符串字节流 为什么?发送效率变高

反序列化:将字符串字节流转换成结构化数据 为什么?方便与提取有效字段

协议定制procotol

1.直接传递struct

可以,但使用范围很小

2.自己实现序列化反序列化

前备

客户端发送到服务端,send/write函数其实是将自己的缓冲区拷贝到发送的缓冲区 ,并没有经过网络。发送缓冲区的数据,发多少,怎么发,出错怎么办,一致由Tcp协议决定 ,Tcp实际通信的时候,是由双方操作系统之间进行通信,同理read/recv也是拷贝函数,将接收缓冲区拷贝到用户缓冲区。

既然send/write是拷贝函数,也就是说当接收缓冲区为空,发送缓冲区为满,双方进程都会被阻塞住。

Tcp为什么是全双工通信协议?

当客户端进行发送,服务端进行接收的同时,服务端也可以进行发送,客户端进行接收

当我们发送helloworld的时候,对方一定收到helloworld吗?

不一定,当服务端的接受缓冲区只剩5个字节了,客户端以为自己发了10个字节,但事实上服务端此时只能读取到5个字节。这种特点我们叫做面向字节流

所以我们得明确报文和报文之间的边界

我们要解决的问题

a.解决结构化数据的序列化和反序列化

本质上是把结构化字段转换为字符串

b.解决用户区分报文边界问题

加入\n进行判断

cpp 复制代码
namespace Proc_wrok
{
    const string Seq = " ";
    const string LineSep = "\n";
    //a op b
    //len\na op b\n
    void Encode(string & message)
    {
        int len=message.size();
        message=to_string(len)+LineSep+message+LineSep;
    }
    //len\na op b\n
    //len
    //len\n
    //len\na op b
    //len\na op b\n
    //len\na op b\nlen\n
    //a op b
    bool Decode(string & Package,string * message)
    {
      
        auto LineSepPos=Package.find("\n");
        if(LineSepPos==string::npos) return false;

        int messagelen=stoi(Package.substr(0,LineSepPos));
      
        int lensize=(Package.substr(0,LineSepPos)).size();
      
        //没有完整的报文
        int total_size=messagelen+LineSep.size()*2+lensize;
      
        if(Package.size()<total_size) return false;  
        //有完整的报文
      
        *message=Package.substr(LineSepPos+LineSep.size(),messagelen);
        //cout<<"有完整的报文:"<<*message<<endl;
        Package.erase(0,total_size);
        return true;
    }
    class Request
    {
    public:
        Request() {}
        Request(int data_a, int data_b, char oper)
            : _data_a(data_a), _data_b(data_b), _oper(oper)
        {
        }
        void PrintDebug()
        {
            cout << "[" << _data_a << "]"
                 << _oper
                 << "[" << _data_b << "]"
                 << "=?" << endl;
        }
        void testDebug()
        {
            _data_a++;
            _data_b++;
        }
        // a op b
        void Serializa(string *message)
        {
            string left = to_string(_data_a);
            string right = to_string(_data_b);
            *message = left + Seq + _oper + Seq + right;
        }
        // a op b
        bool DesSerializa(string &message)
        {
            auto left = message.find(Seq);
            if (left == string::npos)
                return false;

            auto right = message.rfind(Seq);
            if (right == string::npos)
                return false;

            string numa = message.substr(0, left);

            string oper = message.substr(left + 1, right - (left + 1));
            if (oper.size() != 1)
            {
                cout << "Sep error" << endl;
                return false;
            }

            string numb = message.substr(right + 1);

            _data_a = stoi(numa);
            _data_b = stoi(numb);
            _oper = oper[0];
            return true;
        }
        int GetA()
        {
            return _data_a;
        }
        int GetB()
        {
            return _data_b;
        }
        char GetOper()
        {
            return _oper;
        }
    private:
        int _data_a;
        int _data_b;
        char _oper;
    };

    class Result
    {
    public:
        Result() {}
        Result(int result, int code)
            : _result(result), _code(code)
        {
        }
        void Serializa(string *message)
        {
            string left = to_string(_result);
            string right = to_string(_code);
            *message = left + Seq + right;
        }
        // result code
        bool DesSerializa(string &message)
        {
            auto mid = message.find(Seq);
            if (mid == string::npos)
                return false;

            string result = message.substr(0, mid);

            string code = message.substr(mid + 1);

            _result = stoi(result);
            _code = stoi(code);
            return true;
        }
         int GetResult()
        {
            return _result;
        }
        int GetCode()
        {
            return _code;
        }
    private:
        int _result;
        int _code;
    };

   
}

3.引入成熟的序列化反序列化

JSON

sudo yum install jsoncpp-devel 安装Jsoncpp库

JSON 版本的序列化与反序列化

cpp 复制代码
void Serializa(string *message)
        {
         
          
            Json::Value root;
            Json::FastWriter writer;
            root["_data_a"]=_data_a;
            root["_data_b"]=_data_b;
            root["_oper"]=_oper;

          
            *message=writer.write(root);
        }
        // a op b
        bool DesSerializa(string &message)
        {
          
            Json::Value root;
            Json::Reader reader;
            bool retbool=reader.parse(message,root);
            _data_a=root["_data_a"].asInt();
            _data_b=root["_data_b"].asInt();
            _oper=(char)(root["_oper"].asInt());
            return retbool;
        }
相关推荐
Ajiang28247353041 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
中云DDoS CC防护蔡蔡1 小时前
微信小程序被攻击怎么选择高防产品
服务器·网络安全·微信小程序·小程序·ddos
HPC_fac130520678162 小时前
以科学计算为切入点:剖析英伟达服务器过热难题
服务器·人工智能·深度学习·机器学习·计算机视觉·数据挖掘·gpu算力
yaoxin5211233 小时前
第二十七章 TCP 客户端 服务器通信 - 连接管理
服务器·网络·tcp/ip
内核程序员kevin3 小时前
TCP Listen 队列详解与优化指南
linux·网络·tcp/ip
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
‘’林花谢了春红‘’5 小时前
C++ list (链表)容器
c++·链表·list
搬砖的小码农_Sky7 小时前
C语言:数组
c语言·数据结构
sinat_384241097 小时前
使用 npm 安装 Electron 作为开发依赖
服务器
机器视觉知识推荐、就业指导7 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++