【网络】应用层协议(自定义协议)(序列和反序列化)
创始人
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层模型

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

相关内容

热门资讯

lg手机安卓系统卸载,释放存储... 你有没有遇到过这种情况?新买的LG手机,功能强大,外观时尚,就是那些预装的软件让你头疼不已。它们不仅...
微软如何换安卓系统,Windo... 哇塞,你有没有想过,你的安卓手机竟然可以变身成Windows 10系统?没错,就是那个曾经风靡一时的...
安卓系统快还是ios系统快,谁... 你有没有想过,为什么你的手机有时候打开应用慢吞吞的,而朋友的手机却像闪电一样快?这背后,其实就是安卓...
安卓系统查看功能设置,从基础到... 亲爱的手机控们,你是否曾好奇过,你的安卓手机里藏着哪些神秘的设置功能?今天,就让我带你一起探索这个小...
陌陌安卓系统充值,教你轻松省钱... 揭秘陌陌安卓系统充值全攻略:轻松解锁虚拟货币,畅享社交乐趣Hey,亲爱的陌陌用户们,你是否曾在某个瞬...
安卓如何修改系统信息,轻松自定... 亲爱的手机控们,你是否曾好奇过,如何让你的安卓手机焕然一新,仿佛变成了一台全新的设备?没错,今天我要...
安卓系统的研发人,安卓系统研发... 你知道吗?在我们每天不离手的智能手机里,有一个超级厉害的操作系统,它就是安卓系统。而这个系统的背后,...
安卓系统下载pi币,开启数字货... 你有没有听说最近安卓系统上的一款新币种——pi币?这可是个让人眼前一亮的小玩意儿,今天就来给你详细说...
安卓4.2.1系统软件,功能升... 你有没有发现,手机里的系统软件就像是个贴心的管家,默默守护着你的手机生活。今天,咱们就来聊聊安卓4....
安卓系统怎么有表情,安卓系统表... 你知道吗?现在手机聊天,没有表情包简直就像吃饭没放盐一样,少了点意思。那么,安卓系统里的表情包是怎么...
安卓系统映客美颜,直播美颜新体... 亲爱的手机控们,你们有没有发现,现在不管是聊天还是直播,美颜功能简直成了必备神器!今天,咱们就来聊聊...
安卓系统图形界面,安卓系统图形... 探秘安卓系统图形界面的魅力之旅 亲爱的读者们,你是否曾在手机上滑动过屏幕,点开过一个个应用,享受着那...
安卓手机应用苹果系统,探索跨平... 你有没有想过,你的安卓手机也能穿上苹果的“外衣”?没错,就是那种让人一看到就忍不住多看几眼的苹果系统...
酷开系统更换安卓系统吗,轻松更... 亲爱的电视迷们,你是否曾想过,家里的电视系统也能像手机一样,随心所欲地更换呢?今天,就让我带你一探究...
安卓系统设置学生模式,家长无忧... 亲爱的手机控们,你们有没有想过,手机也能变身成为学习的小助手呢?没错,就是那个安卓系统里的神秘功能—...
安卓系统查找朋友app,揭秘热... 你有没有想过,在安卓手机上,如何轻松找到那些让你心动不已的朋友呢?别急,今天就来给你揭秘几个超实用的...
苹果芯片装安卓系统,探索软硬件... 亲爱的读者们,你是否曾经想过,如果把苹果的芯片装进安卓的手机里,会是怎样的景象呢?今天,就让我们一起...
安卓刷回老系统,安卓系统升级后... 亲爱的手机控们,你们有没有遇到过这种情况:新系统更新后,手机变得卡顿,或者某些功能突然不灵光了。别急...
安卓系统官方设计文档,Andr... 亲爱的读者们,你是否曾在某个午后,坐在窗边,手捧一杯香浓的咖啡,翻阅着那些关于安卓系统的神秘文档?今...
安卓系统文件存取总结,Andr... 手机里的文件存取,这可是个让人又爱又恨的小麻烦。你有没有想过,那些藏在安卓系统深处的文件,其实就像是...