应用层协议(自定义协议)(序列和反序列化)
- 一、引言--应用层的使用
- 二、应用层
- 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 <signal.h>
#include <functional>
using func_t = std::function<std::string(std::string &package)>;
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 <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstring>
#include <string>
#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 <iostream>
#include <unistd.h>
#include <cassert>
#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 <jsoncpp/json/json.h>
使用:
 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 <iostream>
#include <string>
#include <jsoncpp/json/json.h>
// #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层模型

 这三层不在内核中实现,是我们手动实现。
















![[Meachines] [Easy] Admirer Adminer远程Mysql反向+Python三方库函数劫持权限提升](https://img-blog.csdnimg.cn/img_convert/2ae56e3d3f963ca40a810a57aa30fb99.jpeg)


