【Linux】:自定义协议(应用层)

朋友们、伙计们,我们又见面了,本期来给大家带来应用层自定义协议相关的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

目录

1. 协议

2. 自定义协议

2.1 预备工作 

3. 序列与反序列化

3.1 报头的添加与解析

3.2 计算业务

4. 功能完善

4.1 服务端

4.2 客户端 

5. 成熟的序列反序列化方案


1. 协议

前面说过,协议其实就是一种约定,我们实现的tcp通信时,都是按照字符串的方式进行发送的,那么对方收到的也是字符串,那么如果我们需要发送一些具体化的数据呢?

就比如:现在使用的这些聊天软件,我们在发送数据时,有昵称、时间、具体的消息内容,因此,在发送数据时,不仅仅是将消息内容发送过去,而是将这三样东西发送过去了,这是一种结构化的数据;

  • 所以在发送类似与这种结构化字段的数据就要制定一种协议;
  • 协议其实就是双方在通信时约定好的一种结构化字段;

在应用层这里我们发送时并不是直接将这个结构化的字段发送给对方:

  • 因为在应用层很可能双方系统有所差异,对于结构体的计算不统一,导致数据的不准确;
  • 所以,在应用层这里,我们要发送结构化的字段,必须要将结构化字段进行序列化成为字节流(“字符串”),将字节流发送给对方,对方通过反序列化将字节流转化为结构化字段;
  • 序列化的目的是为了更好的网络发送,反序列化的目的是为了上层更好的对数据进行有效字段的提取;
  • 序列化和反序列化的方式双方可以进行统一的约定;

2. 自定义协议

在自定协议这里我们直接实现一个网络版本的计算器来提现一下自定义协议的过程;

我们采用分模块来实现:

  • Socket.hpp:对网络套接字进行封装
  • TcpServer.hpp:实现Tcp的服务器
  • TcpServerMain.cc:测试Tcp服务器
  • TcpClientMain.cc:完成客户端
  • Protocol.hpp:自定义协议
  • Calculate.hpp:实现计算的业务

2.1 预备工作 

既然要进行网络通信,那么就少不了需要套接字接口,前面已经写过好多次套接字的接口了,这里对套接字进行封装,将服务器和客户端各自使用的接口整合在一起,我们对封装好的套接字提供一些我们需要的接口接口;

我们之前发送数据使用的read和write,其实还有两个接口:


Socket.hpp:

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#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;  // 读取信息
        virtual void Send(std::string &send_str) = 0;    // 发送信息

    public:
        // 创建监听套接字----Server
        void BuildListenSocketMethod(uint16_t port, int blacklog)
        {
            CreateSocketorDie();
            BindSocketorDie(port);
            ListenSocketorDie(blacklog);
        }
        // 创建连接套接字---Client
        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;
            local.sin_family = AF_INET;
            local.sin_port = htons(port);
            local.sin_addr.s_addr = INADDR_ANY;
            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)
 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stackY、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值