【网络】应用层协议(自定义协议)(序列和反序列化)
创始人
2024-09-24 19:32:03
0

应用层协议(自定义协议)(序列和反序列化)

  • 一、引言--应用层的使用
  • 二、应用层
    • 1、网络版本计算器
      • (1)协议定制和序列反序列化
      • (2)网络版计算器协议定制
        • i、封装有效载荷(默认上面图是Request的,下面图是Response的)
        • ii、封装报头(单独出来的函数)
        • iii、分离有效载荷(默认上面图是Request的,下面图是Response的)
        • iv、解析报文(单独出来的函数)
        • v、测试结果
      • (3)计算器函数
      • (4)计算器与网络连接(网络服务代码)
      • (5)附加:Socket封装
      • (6)服务端代码
      • (7)测试结果
        • 测试结果Debug
        • 解决方法:每一次都删掉规定好的报文
      • (8)客户端编写
      • (9)客户端多个请求同时发送
    • 2、json(用来自动支持序列反序列化)
    • 3、用json进行序列反序列化结果
  • 三、重谈OSI7层模型


一、引言–应用层的使用

在这里插入图片描述

二、应用层

协议是一种 “约定”. socket api的接口, 在读写数据时, 都是按 “字符串” 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢?

1、网络版本计算器

(1)协议定制和序列反序列化

在这里插入图片描述

结构化数据,所有主机都要是一样的结构体类型(协议的定制),再通过网络的序列和反序列化方便数据的收发。

(2)网络版计算器协议定制

在这里插入图片描述
在这里插入图片描述

i、封装有效载荷(默认上面图是Request的,下面图是Response的)

其实就是将这个结构体转化成为"x op y"!和"result code"!
在这里插入图片描述
在这里插入图片描述

ii、封装报头(单独出来的函数)

“len”\n"s"

在这里插入图片描述

iii、分离有效载荷(默认上面图是Request的,下面图是Response的)

将string s 进行分离出来,分离成整型或者char类型的。
在这里插入图片描述
在这里插入图片描述

iv、解析报文(单独出来的函数)

在这里插入图片描述

v、测试结果

在这里插入图片描述

(3)计算器函数

CalHelper函数是进行完加减乘除取模后返回结果的函数,Calculator是将计算结果进行封装完报头的函数。

    Response CalHelper(const Request &req)     {         Response resp(0, 0);         switch (req.op)         {         case '+':             resp.result = req.x + req.y;             break;         case '-':             resp.result = req.x - req.y;             break;         case '*':             resp.result = req.x * req.y;             break;         case '/':         {             if (req.y == 0)             {                 resp.code = DIVERRO;             }             else             {                 resp.result = req.x / req.y;             }             break;         }         case '%':         {             if (req.y == 0)             {                 resp.code = MOERROR;             }             else             {                 resp.result = req.x % req.y;             }             break;         }         default:             resp.code = OTHERERROR;             break;         }         return resp;     }     // "len"\n"10 + 20"\n     std::string Calculator(std::string &package)     {         std::string content;         bool r = Decode(package, &content); // 分离出有效载荷 // "len"\n"10 + 20"\n         if (!r)         {             return "";         }         // 反序列化 -- 分离开每一个元素         Request req;         r = req.Deserialize(content); // x=10 op=+ y=20         if (!r)         {             return "";         }         // 处理结果         content = "";         Response resp = CalHelper(req); // result=30 code=0         // 序列化         resp.Serialize(&content); // "30 0"         // 封装报头         content = Encode(content); // "len"\n"30 0"\n         return content;     } 

(4)计算器与网络连接(网络服务代码)

代码逻辑为:InitTcpServer函数是用来进行监听套接字的设置绑定和监听的,RunTcpServer函数是用来将底层的监听套接字拿到上层来使用并进行提供服务的。

#pragma once  #include "Log.hpp" #include "Socket.hpp" #include  #include   using func_t = std::function;  class TcpServer { public:     TcpServer(uint16_t port, func_t callback)         : _port(port), _callback(callback)     {     }     bool InitTcpServer()     {         _listensocketfd.Socket();         _listensocketfd.Bind(_port);         _listensocketfd.Listen();         lg(Info, "init servercal...");         return true;     }     void RunTcpServer()     {         signal(SIGCHLD, SIG_IGN);         signal(SIGPIPE, SIG_IGN);         while (true)         {             std::string clientip;             uint16_t clientport;             int socketfd = _listensocketfd.Accept(&clientip, &clientport);             if (socketfd < 0)             {                 continue;             }             lg(Info, "accept a new link..., sockfd:%d, clientip:%s, clientport:%d", socketfd, clientip.c_str(), clientport);             // 提供服务             // pid_t id = fork();             if (fork() == 0)             {                 _listensocketfd.Close();                 std::string inbuffer_stream;                 // 数据计算                 while (true)                 {                     char buffer[128];                     ssize_t n = read(socketfd, buffer, sizeof(buffer));                     if (n > 0)                     {                         buffer[n] = 0;                         inbuffer_stream += buffer;                          lg(Debug, "debug:%s", inbuffer_stream.c_str());                         // while (true)                         //{                         std::string info = _callback(inbuffer_stream);                         if (info.empty())                             continue;                         // break;                         // lg(Debug, "debug, response:\n%s", info.c_str());                         // lg(Debug, "debug:\n%s", inbuffer_stream.c_str());                         write(socketfd, info.c_str(), info.size());                         //}                     }                     else if (n == 0)                     {                         break;                     }                     else                         break;                 }                  exit(0);             }             close(socketfd);         }     }     ~TcpServer()     {     }  private:     Sock _listensocketfd;     uint16_t _port;     func_t _callback; }; 

回调函数示意:
在这里插入图片描述

(5)附加:Socket封装

#pragma once  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include "Log.hpp"  //extern Log lg;  enum {     SOCKETERR = 2,     BINDERR,     LISTENERR };  const int backlog = 10;  class Sock { public:     Sock()     {     }     ~Sock()     {     }  public:     void Socket()     {         _socketfd = socket(AF_INET, SOCK_STREAM, 0);         if (_socketfd < 0)         {             lg(Fatal, "socket create err, %d:%s", errno, strerror(errno));             exit(SOCKETERR);         }     }     void Bind(uint16_t port)     {         struct sockaddr_in local;         memset(&local, 0, sizeof(local));         local.sin_family = AF_INET;         local.sin_port = htons(port);         local.sin_addr.s_addr = INADDR_ANY;         if (bind(_socketfd, (struct sockaddr *)&local, sizeof(local)) < 0)         {             lg(Fatal, "bind error, %d:%s", errno, strerror(errno));             exit(BINDERR);         }     }     void Listen()     {         if (listen(_socketfd, backlog) < 0)         {             lg(Fatal, "listen error, %d:%s", errno, strerror(errno));             exit(LISTENERR);         }     }     int Accept(std::string *clientip, uint16_t *clientport)     {         struct sockaddr_in peer;         socklen_t len = sizeof(peer);         int newfd = accept(_socketfd, (struct sockaddr *)&peer, &len);         if (newfd < 0)         {             lg(Warning, "accept error, %d:%s", errno, strerror(errno));             return -1;         }         char ipstr[64];         inet_ntop(AF_INET, &(peer.sin_addr), ipstr, sizeof(ipstr));         *clientip = ipstr;         *clientport = ntohs(peer.sin_port);         return newfd;     }     int Connect()     {         return 0;     }     void Close()     {         close(_socketfd);     }  private:     int _socketfd; }; 

(6)服务端代码

#include "TcpServer.hpp" #include "Protocol.hpp" #include "Servercal.hpp"  static void Usage(const std::string &proc) {     std::cout << "\nUsage" << proc << " port\n\n" << std::endl; }  int main(int argc, char *argv[]) {     if (argc != 2)     {         Usage(argv[0]);         exit(0);     }     uint16_t clientport = std::stoi(argv[1]);     ServerCal cal;     TcpServer *tsvp = new TcpServer(clientport, std::bind(&ServerCal::Calculator, &cal, std::placeholders::_1));     tsvp->InitTcpServer();     tsvp->RunTcpServer();     return 0; } 

(7)测试结果

在这里插入图片描述

测试结果Debug

在这里插入图片描述

解决方法:每一次都删掉规定好的报文

在这里插入图片描述

(8)客户端编写

Socket.hpp:
在这里插入图片描述
ClientCal.cc:

#include  #include  #include  #include "Socket.hpp" #include "Protocol.hpp"  static void Usage(const std::string &proc) {     std::cout << "\nUsage" << proc << " serverip: serverport\n\n"               << std::endl; }  // ./clientcal 127.0.0.1 8888 int main(int argc, char *argv[]) {     if (argc != 3)     {         Usage(argv[0]);         exit(0);     }     uint16_t serverport = std::stoi(argv[2]);     std::string serverip = argv[1];     Sock socketfd;     socketfd.Socket();     bool r = socketfd.Connect(serverip, serverport);     if (!r)         return 1;      srand(time(nullptr) ^ getpid());     int cnt = 1;     const std::string opers = "+-*/%=^";     std::string inbuffer_stream;     while (cnt <= 10)     {         std::cout << "===============第" << cnt << "次测试....., " << "===============" << std::endl;         int x = rand() % 100 + 1;         usleep(1234);         int y = rand() % 100;         usleep(4321);         char oper = opers[rand() % opers.size()];         Request req(x, y, oper);         req.DebugPrint();          std::string package;         req.Serialize(&package);         package = Encode(package);         std::cout << "这是新的发出去的请求:\n" << package;         write(socketfd.Fd(), package.c_str(), package.size());          char buffer[128];         ssize_t n = read(socketfd.Fd(), buffer, sizeof(buffer)); // 保证不了读到的是一个完整的报文         if (n > 0)         {             buffer[n] = 0;             inbuffer_stream += buffer;             std::string content;             bool rqs = Decode(inbuffer_stream, &content);             assert(rqs);              Response resp;             rqs = resp.Deserialize(content);             assert(rqs);              resp.DebugPrint();         }         std::cout << "=================================================" << std::endl;         sleep(1);         cnt++;     }     socketfd.Close();     return 0; } 

测试结果:
在这里插入图片描述

(9)客户端多个请求同时发送

在这里插入图片描述

在这里插入图片描述

2、json(用来自动支持序列反序列化)

安装命令:sudo yum install -y jsoncpp-devel
在这里插入图片描述
安装成功:
在这里插入图片描述

头文件:

#include  

使用:
FastWriter:
测试用例一(序列化):

int main() {     Json::Value part1;     part1["haha"] = "haha";     part1["hehe"] = "hehe";       Json::Value root;     root["x"] = 100;     root["y"] = 200;     root["op"] = '+';     root["desc"] = "this is a + oper";     root["test"] = part1;      Json::FastWriter w;     std::string res = w.write(root);      std::cout << res << std::endl;     return 0; } 

编译:
g++ test.cc -ljsoncpp
在这里插入图片描述
测试用例二(反序列化):
FastWriter:

int main() {     Json::Value part1;     part1["haha"] = "haha";     part1["hehe"] = "hehe";       Json::Value root;     root["x"] = 100;     root["y"] = 200;     root["op"] = '+';     root["desc"] = "this is a + oper";     root["test"] = part1;      Json::FastWriter w;     std::string res = w.write(root);          sleep(3);      Json::Value v;     Json::Reader r;     r.parse(res, v);      int x = v["x"].asInt();     int y = v["y"].asInt();     char op = v["op"].asInt();     std::string desc = v["desc"].asString();     Json::Value temp = v["test"];     std::cout << x << std::endl;     std::cout << y << std::endl;     std::cout << op << std::endl;     std::cout << desc << std::endl;     return 0; } 

在这里插入图片描述

测试用例三(序列化):
StyleWriter:

int main() {     Json::Value part1;     part1["haha"] = "haha";     part1["hehe"] = "hehe";       Json::Value root;     root["x"] = 100;     root["y"] = 200;     root["op"] = '+';     root["desc"] = "this is a + oper";     root["test"] = part1;      Json::StyleWriter w;     std::string res = w.write(root);      std::cout << res << std::endl;     return 0; } 

在这里插入图片描述

3、用json进行序列反序列化结果

Makefile:

.PHONY:all all:servercal clientcal  Flag=-DMySelf=1 Lib=-ljsoncpp  servercal:ServerCalculator.cc 	g++ -o $@ $^ -std=c++11 $(Lib) #$(Flag) clientcal:ClientCalculator.cc 	g++ -o $@ $^ -std=c++11 $(Lib) #$(Flag)  .PHONY:clean clean: 	rm -f servercal clientcal 

Protocol.hpp:

#pragma once // 定制协议 #include  #include  #include   // #define MySelf 1  const std::string blank_space_sep = " "; const std::string protocol_sep = "\n";  std::string Encode(std::string &content) {     // 封装报头     std::string package = std::to_string(content.size());     package += protocol_sep;     package += content;     package += protocol_sep;     return package; }  bool Decode(std::string &package, std::string *content) // "len"\n"x op y"\n {     // package = len_str + content_str + 2 总长度等于长度字符串长度+正文长度+两个\n的长度     size_t pos = package.find(protocol_sep);     if (pos == std::string::npos)     {         return false;     }     std::string len_str = package.substr(0, pos);     // 分理出长度     size_t len = std::stoi(len_str);     size_t total_len = len_str.size() + len + 2;     if (package.size() < total_len)     {         return false;     }     // 完整报文--提取有效载荷     *content = package.substr(pos + 1, len);     // 移除报文,防止多余报文影响     package.erase(0, total_len);     return true; }  class Request { public:     Request(int data1, int data2, char oper)         : x(data1), y(data2), op(oper)     {     }     Request()     {     }  public:     bool Serialize(std::string *out)     { #ifdef MySelf         // 构建有效载荷         // struct --> string "x op y" => "len"\n"x op y"         std::string s = std::to_string(x);         s += blank_space_sep;         s += op;         s += blank_space_sep;         s += std::to_string(y);          *out = s; #else         Json::Value root;         root["x"] = x;         root["y"] = y;         root["op"] = op;         Json::FastWriter w;         *out = w.write(root); #endif         return true;     }     bool Deserialize(const std::string &in) // "x op y"     { #ifdef MySelf         size_t leftpos = in.find(blank_space_sep);         if (leftpos == std::string::npos)         {             return false;         }         std::string part_x = in.substr(0, leftpos);          size_t rightpos = in.rfind(blank_space_sep);         if (rightpos == std::string::npos)         {             return false;         }         std::string part_y = in.substr(rightpos + 1);         if (leftpos + 1 != rightpos - 1)         {             return false;         }         op = in[leftpos + 1];         x = std::stoi(part_x);         y = std::stoi(part_y); #else         Json::Value root;         Json::Reader r;         r.parse(in, root);          x = root["x"].asInt();         y = root["y"].asInt();         op = root["op"].asInt(); #endif         return true;     }     void DebugPrint()     {         std::cout << "新请求构建完成:" << x << op << y << "=?" << std::endl;     }  public:     int x;     int y;     char op; // +-*/ };  class Response { public:     Response(int res, int c)         : result(res), code(c)     {     }     Response()     {     }  public:     bool Serialize(std::string *out)     { #ifdef MySelf         // 构建有效载荷         // "len"\n"result code"         std::string s = std::to_string(result);         s += blank_space_sep;         s += std::to_string(code);          *out = s; #else         Json::Value root;         root["result"] = result;         root["code"] = code;         Json::FastWriter w;         *out = w.write(root); #endif         return true;     }     bool Deserialize(const std::string &in) // "result code"     { #ifdef MySelf         size_t pos = in.find(blank_space_sep);         if (pos == std::string::npos)         {             return false;         }         std::string res = in.substr(0, pos);         std::string cod = in.substr(pos + 1);         result = std::stoi(res);         code = std::stoi(cod); #else         Json::Value root;         Json::Reader r;         r.parse(in, root);          result = root["result"].asInt();         code = root["code"].asInt(); #endif         return true;     }     void DebugPrint()     {         std::cout << "结果响应完成, 结果是:" << "result:" << result << "  " << "code:" << code << std::endl;     }  public:     int result;     int code; // 0表示可信,非零表示不可信,相对应的数字表示相对应的错误原因 }; 

在这里插入图片描述

三、重谈OSI7层模型

在这里插入图片描述
这三层不在内核中实现,是我们手动实现。

相关内容

热门资讯

安卓系统为什么不封闭,揭秘安卓... 你有没有想过,为什么安卓系统那么开放,却不像苹果iOS那样封闭呢?这背后可是有着不少有趣的故事和原因...
安卓系统更新包多大,解析不同版... 你有没有发现,每次安卓系统更新,手机里都会多出那么几个G的文件?这可真是让人好奇,安卓系统更新包究竟...
安卓手机安装双系统吗,安卓手机... 你有没有想过,你的安卓手机是不是也能像电脑一样,装上两个系统,一个用来工作,一个用来娱乐?没错,这就...
oppo会升级安卓系统,畅享最... 你知道吗?最近有个大消息在手机圈里炸开了锅,那就是OPPO要升级安卓系统啦!这可不是什么小打小闹的更...
安卓系统上安装windows,... 你有没有想过,在安卓手机上安装Windows系统?听起来是不是有点不可思议?但你知道吗,这竟然是可能...
安卓系统怎么进运行框,安卓系统... 你有没有想过,你的安卓手机里有一个超级实用的功能,那就是运行框!它就像是一个小助手,帮你快速找到正在...
安卓系统电视无图像设置,安卓电... 你家的安卓系统电视突然没图像了?别急,让我来给你支个招,让你轻松解决这个问题!一、检查电源和连接线首...
安卓机建议升级系统吗,提升性能 你有没有发现,你的安卓手机最近有点儿慢吞吞的?是不是在犹豫要不要升级系统呢?别急,让我来给你好好分析...
升级不了安卓系统升级,探寻升级... 你有没有遇到过这种情况?手机里的安卓系统突然告诉你,它需要升级,但你左等右等,就是升不上去。这可真是...
备用安卓系统手机推荐,盘点热门... 你有没有想过,如果你的手机突然罢工了,你会怎么办?别担心,今天我就要给你安利几款备用安卓系统手机,让...
旧安卓系统ipad无法更新系统... 你有没有遇到过这种情况?你的旧安卓系统iPad突然告诉你,它无法更新系统了!是不是瞬间感觉心里有点小...
运行安卓6系统命令大全,全面掌... 你有没有想过,你的安卓手机里隐藏着无数强大的功能,只等着你去发现和探索呢?今天,就让我带你走进安卓6...
安卓系统简笔画教程下载,轻松绘... 你有没有想过,用简单的线条就能把复杂的安卓系统画出来?没错,就是那种一看就懂,一画就上手的感觉!今天...
华为如何鸿蒙转安卓系统,轻松实... 你知道吗?最近华为的大动作可是让整个科技圈都沸腾了!他们竟然把鸿蒙系统转到了安卓系统上,这可真是让人...
安卓10系统的问题,安卓10系... 你有没有发现,自从你的手机升级到安卓10系统后,好像有点不对劲呢?别急,让我来给你细细道来,看看安卓...
安卓系统苹果搞笑视频,苹果搞笑... 你知道吗?在互联网的世界里,搞笑视频可是个永恒的热门话题。尤其是那些结合了安卓系统和苹果手机的搞笑片...
卡片机改造安卓系统,探索改造之... 你有没有想过,那些曾经陪伴我们记录美好时光的卡片机,现在竟然也能焕发第二春呢?没错,就是那些小巧便携...
装安卓系统倒车出不来,智能科技... 你有没有遇到过这样的事情:手机装了个安卓系统,结果倒车的时候出不来啦?这可不是闹着玩的,简直让人抓狂...
定制安卓系统哪家好点儿,哪家服... 你有没有想过,手机系统就像是个人的衣服,每个人都需要找到最适合自己的那一款?今天,咱们就来聊聊定制安...
台电用回安卓系统吗,开启智能新... 最近有个话题在科技圈里炒得挺热的,那就是台电是不是要用回安卓系统了?你有没有想过,这个小小的决定背后...