当前位置: 首页 > news >正文

Socket封装---模板方法类

目录

一、模板方法类

二、Socket的框架

三、TCPSocket对父类的虚函数重写


       在平时写网络代码的时候,经常会涉及到socket套接字的部分,这一部分用的十分频繁,但是流程都是固定的,我实在是饱受其苦,但是由于C++不像java一样有已经封装好的socket和serverSock类。所以我在想能不能自己把套接字封装一下,这样以后在使用的时候就会十分便捷。

一、模板方法类

        模板方法模式(Template Method Pattern)是一种行为设计模式,它在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变算法的结构即可重定义算法的某些特定步骤。

        模板方法类通常适用于固定的步骤,但是不同人使用这个相同的步骤可能会有细小的差别。

二、Socket的框架

        唯一要注意的一点就是这里使用了智能指针,将Socket包裹成了shared_ptr,但是使用SockPtr的时候,仍然可以传他的子类TCPSocket进去,以后还是能用SockPtr来调用成员函数的。从这里可以体现出继承和多态的特性。

class Socket;
    //因为这里要用到Socket这个类,但是此时他还没有被定义出来,所以我们在他前面声明一下,告诉编译器他的定义在后面,让我们在这一行可以使用他
    using SockPtr = std::shared_ptr<Socket>;
    
    // 基本套接字:只负责提供接口,他的子类通过让接口做组合,完成固定的逻辑
    class Socket
    {
    public:
        
    public:
        virtual void CreateSocketOrDie() = 0;
        virtual void CreateBindOrDie(uint16_t port) = 0;
        virtual void CreateListenOrDie(int backlog = gbacklog) = 0;
        virtual SockPtr Accepter(InetAddr *clientAddr) = 0;
        virtual bool Connector(const std::string& peerip,uint16_t peerport) = 0;
        virtual int sockfd()=0;
        virtual void Close()=0;

        virtual int Recv(std::string* out)=0;
        virtual int Send(const std::string& in)=0;

    public:
        //父类中只是对虚函数进行组合,以固定的逻辑顺序执行函数组合。
        //但是实际上调用的时候用父类的指针或者引用调用BuildListenSocket这种函数,会走子类重写的函数,这是多态的特性
        void BuildListenSocket(uint16_t port)
        {
            // 1.创建套接字
            CreateSocketOrDie();
            // 2.绑定
            CreateBindOrDie(port);
            // 3.设置监听状态
            CreateListenOrDie();
        }

        bool BuildClientSocket(const std::string& peerip,uint16_t peerport)
        {
            //1.创建套接字
            CreateSocketOrDie();
            //2.连接
            return Connector(peerip,peerport);
        }
        
    };

三、TCPSocket对父类的虚函数重写

class TcpSocket : public Socket
    {
    public:
        TcpSocket() {}
        TcpSocket(int sockfd) : _sockfd(sockfd)
        {}
        ~TcpSocket()
        {}

        void CreateSocketOrDie() override
        {
            // 1. 创建socket
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                LOG(FATAL, "socket create error\n");
                exit(SOCKET_ERROR);
            }
            LOG(INFO, "socket create success, sockfd: %d\n", _sockfd); // 3
        }
        void CreateBindOrDie(uint16_t port) override
        {
            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;

            // 2. bind sockfd 和 Socket addr
            if (::bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                LOG(FATAL, "bind error\n");
                exit(BIND_ERROR);
            }

            LOG(INFO, "bind success, sockfd: %d\n", _sockfd);
        }
        void CreateListenOrDie(int backlog) override
        {
            // 3. 因为tcp是面向连接的,tcp需要未来不断地能够做到获取连接
            if (::listen(_sockfd, backlog) < 0)
            {
                LOG(FATAL, "listen error\n");
                exit(LISTEN_ERR);
            }
            LOG(INFO, "listen success\n");
        }
        SockPtr Accepter(InetAddr *clientAddr) override
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            // 4. 获取新连接
            int sockfd = ::accept(_sockfd, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                LOG(WARNING, "accept error\n");
                return nullptr;
            }
            *clientAddr = InetAddr(client);
            LOG(INFO, "get a new link, client info : %s, sockfd is : %d\n", clientAddr->AddrStr().c_str(), sockfd);
            return std::make_shared<TcpSocket>(sockfd);
        }
        bool Connector(const std::string& peerip,uint16_t peerport) override
        {
            struct sockaddr_in server;
            memset(&server, 0, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(peerport);
            ::inet_pton(AF_INET, peerip.c_str(), &server.sin_addr);

            int n = ::connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
            if (n < 0)
            {
                return false;
            }
            return true;
        }

        int sockfd() override
        {
            return _sockfd;
        }

        void Close() override
        {
            if(_sockfd>0)
            {
                ::close(_sockfd);
            }
        }

        int Recv(std::string* out)override
        {
            char inbuffer[1024]; // 当做字符串
            int n = ::recv(_sockfd, inbuffer, sizeof(inbuffer) - 1,0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                //覆盖式不可取,要使用+=
                *out+=inbuffer;
            }
            return n;
        }
        int Send(const std::string& in)override
        {
            return ::send(_sockfd,in.c_str(),in.size(),0);
        }
        
    private:
        int _sockfd; // 可以是listen也可是普通套接字
    };

    // //使用的时候:
    // Socket* sock=new TcpSocket();
    // sock->BuildListenSocket();

}

这上面除了封装代码,还使用到了LOG日志,这个在我之前的笔记中有写到。当然除了TCP可以对他进行重写,你还可以定义一个UDPSocket类,与上述类似。

http://www.dtcms.com/a/73600.html

相关文章:

  • 【数据库】Data Model(数据模型)数据模型分析
  • 施工企业管理软件:融合协同办公与资源调配功能,助力企业精细化项目管理
  • Nginx面试题
  • 双缓冲机制(含原理、优势、实现方式、应用场景)
  • 字符串哈希从入门到精通
  • 【Linux网络-网络层】TCP与IP的关系+IP协议基本概念+网段划分+路由+IP分片与组装
  • 表达式引擎之活动任务系统设计
  • 《我的Python觉醒之路》之转型Python(十五)——控制流
  • 杰理可视化SDK-手机三方通话控制
  • 如何高效安装和配置WordPress:从基础依赖到高级设置
  • 《笔记》Android 获取第三方应用及查看应用信息、apk大小、缓存、存储,以及第三方清除缓存
  • 用maven生成springboot多模块项目
  • qt介绍图表 charts 一
  • 学习threejs,使用MeshLambertMaterial漫反射材质
  • 自带多个接口,完全免费使用!
  • 第N7周:调用Gensim库训练Word2Vec模型
  • Java---SpringMVC(2)
  • B2B2B 商城模式系统:开启企业高效协作新征程
  • 【C++经典例题】反转字符串中单词的字符顺序:两种实现方法详解
  • 基于关键词的文本知识的挖掘系统的设计与实现
  • 20250317笔记本电脑在ubuntu22.04下使用acpi命令查看电池电量
  • WebGL学习
  • 时尚复古新艺术风品牌海报徽标设计衬线英文字体安装包 Blessing – Art Nouveau Font
  • 【软考-架构】5.3、IPv6-网络规划-网络存储-补充考点
  • log4j2漏洞:反弹shell
  • maven导入本地jar包
  • C++抽象与类的核心概念解析
  • 粗解JQHttpServer
  • 如何优化 TCP/IP 的 NCCL 通信
  • 地图(六)利用python绘制连接地图