自定义协议(应用层协议)——网络版计算机基于TCP传输协议
创始人
2024-12-14 07:35:49

应用层:自定义网络协议:序列化和反序列化,如果是TCP传输的:还要关心区分报文边界(在序列化设计的时候设计好)——粘包问题
——两个问题:粘包、序列化反序列化
在这里插入图片描述

1、首先想要使用TCP协议传输的网络,服务器和客户端都应该要创建自己的套接字,因为两个都要创建,所以我们把套接字封装为一个类:
封装方法:设计模式:模版方法:先写一个模版类(基类),里面有各种函数,然后再写一个派生类里面有各种方法的实现,创建对象的时候

#pragma once #include  #include  #include  #include  #include  #include  #include  #include   #define Convert(addrptr) ((struct sockaddr *)addrptr)  namespace Net_Work {     const static int defaultsockfd = -1;     const int backlog = 5;      enum     {         SocketError = 1,         BindError,         ListenError,     };      // 封装一个基类,Socket接口类     // 设计模式:模版方法类     class Socket     {     public:         virtual ~Socket() {}         virtual void CreateSocketOrDie() = 0;         virtual void BindSocketOrDie(uint16_t port) = 0;         virtual void ListenSocketOrDie(int backlog) = 0;         virtual Socket *AcceptConnection(std::string *peerip, uint16_t *peerport) = 0;         virtual bool ConnectServer(std::string &serverip, uint16_t serverport) = 0;         virtual int GetSockFd() = 0;         virtual void SetSockFd(int sockfd) = 0;         virtual void CloseSocket() = 0;         virtual bool Recv(std::string *buffer, int size) = 0;         // TODO     public:         // 创建服务器端的套接字,并设置为监听状态监听套接字         void BuildListenSocketMethod(uint16_t port, int backlog)         {             CreateSocketOrDie();             BindSocketOrDie(port);             ListenSocketOrDie(backlog);         }         // 创建客户端的套接字,并且申请链接         bool BuildConnectSocketMethod(std::string &serverip, uint16_t serverport)         {             CreateSocketOrDie();             return ConnectServer(serverip, serverport);         }          void BuildNormalSocketMethod(int sockfd)         {             SetSockFd(sockfd);         }     };      class TcpSocket : public Socket     {     public:         TcpSocket(int sockfd = defaultsockfd) : _sockfd(sockfd)         {         }         ~TcpSocket()         {         }         void CreateSocketOrDie() override // 创建套接字         {             _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);             if (_sockfd < 0)                 exit(SocketError);         }         void BindSocketOrDie(uint16_t port) override // 绑定套接字         {             struct sockaddr_in local;             memset(&local, 0, sizeof(local));             local.sin_family = AF_INET;             local.sin_addr.s_addr = INADDR_ANY;             local.sin_port = htons(port);              int n = ::bind(_sockfd, Convert(&local), sizeof(local));             if (n < 0)                 exit(BindError);         }         void ListenSocketOrDie(int backlog) override // 设置套接字为监听状态         {             int n = ::listen(_sockfd, backlog);             if (n < 0)                 exit(ListenError);         }         // 获取链接套接字——服务器         Socket *AcceptConnection(std::string *peerip, uint16_t *peerport) override         {             struct sockaddr_in peer;             socklen_t len = sizeof(peer);             int newsockfd = ::accept(_sockfd, Convert(&peer), &len);             if (newsockfd < 0)                 return nullptr;             *peerport = ntohs(peer.sin_port);             *peerip = inet_ntoa(peer.sin_addr);             Socket *s = new TcpSocket(newsockfd);             return s;         }          // 申请链接——客户端         bool ConnectServer(std::string &serverip, uint16_t serverport) override         {             struct sockaddr_in server;             memset(&server, 0, sizeof(server));             server.sin_family = AF_INET;             server.sin_addr.s_addr = inet_addr(serverip.c_str());             server.sin_port = htons(serverport);              int n = ::connect(_sockfd, Convert(&server), sizeof(server));             if (n == 0)                 return true;             else                 return false;         }         int GetSockFd() override         {             return _sockfd;         }         void SetSockFd(int sockfd) override         {             _sockfd = sockfd;         }         void CloseSocket() override         {             if (_sockfd > defaultsockfd)                 ::close(_sockfd);         }         bool Recv(std::string *buffer, int size)//接收消息到buffer中         {             char inbuffer[size];             ssize_t n = recv(_sockfd, inbuffer, size - 1, 0);             if (n > 0)             {                 inbuffer[n] = 0;                 *buffer += inbuffer;                 return true;             }             else if (n == 0 || n < 0)                 return false;         }          private:             int _sockfd;         };     } 

创建服务器:
1、创建套接字
2、把套接字设置为监听状态
3、获取连接,产生新的套接字
4、把新的套接字作为新线程的参数传到新线程执行的代码中,实现收发消息的操作
在这里插入图片描述
代码:

#pragma once  #include"Socket.hpp" #include #include   using func_t=std::function;  //服务器类 class TcpServer;  class ThreadData {  public:      ThreadData(TcpServer*tcp_this, Net_Work::Socket *sockp): _this(tcp_this), _sockp(sockp)     {}  public:     TcpServer *_this;     Net_Work::Socket *_sockp; };  class TcpServer {     public:     TcpServer(uint16_t port, func_t handler_request):_port(port),_listensocket(new Net_Work::TcpSocket()),_handler_request(handler_request)     {         _listensocket->BuildListenSocketMethod(_port,Net_Work::backlog);     }   static void *ThreadRun(void *args)     {         pthread_detach(pthread_self());//分离线程         ThreadData *td=static_cast(args);         td->_this->_handler_request(td->_sockp);         td->_sockp->CloseSocket();         delete td->_sockp;         delete td;         return nullptr;     }     void Loop()     {         while(true)         {             //获取连接         std::string peerip;         uint16_t peerport;         Net_Work::Socket* newsock=_listensocket->AcceptConnection(&peerip,&peerport);         if(newsock==nullptr) continue;;         std::cout<<"获取了一个新链接,sockfd: "<GetSockFd()<<"client info:"<< peerip<<":"<         delete _listensocket;     }     private:     int _port;     Net_Work::Socket *_listensocket; public:     func_t _handler_request;  };  

客户端:
在这里插入图片描述

2、TCP是向字节流(字符串)

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

序列化、反序列化

自定义协议就是定义双方都认识的结构化字段,并且协议中有序列化和反序列化的实现
先定义一个协议(结构化字段)——双方都能看到
设计模式:工厂模式:
客户端发送的结构体+序列化函数+反序列化函数
在这里插入图片描述

服务器反序列化的接收的结构体+反序列函数+序列化函数
在这里插入图片描述
代码:

#pragma once  #include  #include   namespace Protocol {      const std::string ProtSep = " ";      const std::string LineBreakSep = "\n";      // 封装为报文——序列化的一部分     std::string Encode(const std::string &message) //"x op y"或者"_result _code"     {         std::string len = std::to_string(message.size());         std::string package = len + LineBreakSep + message + LineBreakSep; //"len\n""x op y\n"         return package;     }      // 解报——反序列化的一部分     bool Decode(std::string &package, std::string *message) //"len\n""x op y\n"     {         // 除了解报,我们还要判断是否认正确          auto pos = package.find(LineBreakSep);         if (pos == std::string::npos)             return false;         std::string lens = package.substr(0, pos);         int messagelen = std::stoi(lens);         int total = lens.size() + messagelen + 2 * LineBreakSep.size();         if (package.size() < total)             return false;         // 至少有一个完整报文         *message = package.substr(pos + LineBreakSep.size(), messagelen);         // 收到的报文可能是"len\n""x op y\n""len\n""x op y\n""len\n""x op y\n"         // 所以我解报一个报文后,要删除这个报文,让后面的继续Dcode解报         package.erase(0, total);         return true;     }      class Requset     {     public:         Requset() : _data_x(0), _data_y(0), _oper(0)         {         }         Requset(int x, int y, int op) : _data_x(x), _data_y(y), _oper(op)         {         }         ~Requset()         {         }         void Debug()         {             std::cout << "_data_x:" << _data_x << std::endl;             std::cout << "_data_y:" << _data_y << std::endl;             std::cout << "_oper:" << _oper << std::endl;         }         void Inc()         {             _data_x++;             _data_y++;         }         // 自定义序列化协议:结构体数据->字符串         bool Serialize(std::string *out)         {             //"x op y"             *out = std::to_string(_data_x) + ProtSep + _oper + ProtSep + std::to_string(_data_y);             return true;         }         // 反序列化   :  字符串->结构体数据         bool Deserialize(std::string &in) //"x op y"         {             auto left = in.find(ProtSep);             if (left == std::string::npos)                 return false;             auto right = in.rfind(ProtSep);             if (right == std::string::npos)                 return false;              //[)             _data_x = std::stoi(in.substr(0, left));             _data_y = std::stoi(in.substr(right + ProtSep.size()));             std::string oper = in.substr(left + ProtSep.size(), right - (left + ProtSep.size()));              if (oper.size() == 1)                 return false;             _oper = oper[0];             return true;         }         int Getx() { return _data_x; }         int Gety() { return _data_y; }         char GetOper() { return _oper; }          //_data_x+_data_y         // 报文的自描述         //"len\n""x op y\n"     private:         int _data_x; // 第一个参数         int _data_y; // 第二个参数         char _oper;  //+ - * / %     };      class Response     {     public:         Response(): _rseult(0), _code(0)         {         }         Response(int result, int code) : _result(result), _code(code)         {         }         // 自定义序列化协议:结构体数据->字符串         bool Serialize(std::string *out)         {             //"_result  _code"             *out = std::to_string(_result) + ProtSep + std::to_string(_code);             return true;         }         // 反序列化:字符串->数据架构数据         bool Deserialize(std::string &in) //"_result  _code"         {             auto pos = in.find(ProtSep);             if (pos == std::string::npos)                 return false;             _result = std::stoi(in.substr(0, pos));             _code = std::stoi(in.substr(pos + ProtSep.size()));             return true;         }         void SetResult(int res) { _result = res; }         void SetCode(int code){ _code=code;}      private:         int _result; // 运算结果         int _code;   // 运算状态     };      // 简单的工厂模式,建造类设计模式     class Factory     {     public:         std::shared_ptr BulidRequest()         {             std::shared_ptr req = std::make_shared();             return req;         }         std::shared_ptr BulidRequest(int x, int y, int op)         {             std::shared_ptr req = std::make_shared(x, y, op);             return req;         }         std::shared_ptr BulidResponse()         {             std::shared_ptr resp = std::make_shared();             return resp;         }         std::shared_ptr BulidResponse(int result, int code)         {             std::shared_ptr resp = std::make_shared(result, code);             return resp;         }     }; }  

成熟的序列化反序列化:
Json:Value 万能类型
在这里插入图片描述

那么我们序列化和反序列化就可以用这样的:
在这里插入图片描述

总结:发送的数据为结构体,这个结构体就是我们自定义的协议,他的序列化反序列化 这些都是应用层的协议

相关内容

热门资讯

长光卫星8颗卫星今日出征 将于... 5月17日,长光卫星技术股份有限公司在吉林省航天信息产业园举行“文物01星”、“彩云光学01星”、“...
管网式七氟丙烷气体灭火装置厂家... 导语:管网式七氟丙烷气体灭火装置作为高效环保的消防设备,广泛应用于工业厂房、电力设施、档案馆等场景。...
让好故事更好抵达观众(人文茶座... 牛梦笛 打开手机,嫦娥奔月的故事在AI(人工智能)影像里重现;节气传说、上古神话,在小小屏幕间次第展...
蜂巢能源申请电池模组和电池包专... 国家知识产权局信息显示,蜂巢能源科技股份有限公司申请一项名为“电池模组和电池包”的专利,公开号CN1...
乐道做对了,也稳住了 “两年前,乐道品牌第一次和大家见面。那时候有人问:中国市场还需要一个新品牌吗?纯电品牌真的能活下来吗...