赞
踩
可以使用模块方法
设计模式来设计套接字 socket 的封装
模板方法(Template Method)设计模式是一种行为设计模式,它在一个方法中定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。
抽象类定义了一个模板方法,这个方法通常包含对具体方法的调用,抽象类还定义了一些抽象方法,这些方法会在模板方法中被调用,但具体的实现由子类来提供(抽象类,也就是父类中,将这些方法都设置为纯虚函数,子类要重写纯虚函数),子类通过继承抽象类并提供抽象方法的实现,从而可以自定义模板方法中的某些步骤,当模板方法被调用时,它会按照定义的顺序依次调用抽象类中的抽象方法和具体方法。
#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 }; // 封装一个基类, 套接字对应的接口类 // 一旦一个类中有纯虚函数, 只有被继承并且实现此方法后, 才能创建对象 // ::close 使用系统的接口函数 // 设计模式:模板方法 class Socket { public: virtual ~Socket() {} virtual void CreateSocketOrDie() = 0; // 创建套接字 virtual void BindSocketOrDie(uint16_t port) = 0; // 绑定 virtual void ListenSocketOrDie(int backlog) = 0; // 监听 // 获取连接, 拿到tcp所需的新的文件描述符 newsockfd, 并返回并 create 一个 tcp 套接字, 并将客户端信息通过输出型参数返回 virtual Socket* AcceptConnection(std::string* peerip, uint16_t* peerport) = 0; virtual bool ConnetServer(std::string& serverip, uint16_t serverport) = 0; virtual int GetSockFd() = 0; virtual void SetSockFd(int sockfd) = 0; virtual void CloseSockfd() = 0; public: // 下面这些方法会被子类继承下去 void BulidListenSocketMethod(uint16_t port, int backlog) // 创建监听套接字, 给 Server 用的 { CreateSocketOrDie(); BindSocketOrDie(port); ListenSocketOrDie(backlog); } bool BulidConnectSocketMethod(std::string& serverip, uint16_t serverport) // 创建连接套接字, 给Client 用 { CreateSocketOrDie(); return ConnetServer(serverip, serverport); // connet 有可能会失败 } void BulidNormalSocketMethod(int sockfd) { SetSockFd(sockfd); } }; // 成员函数用 override 修饰后, 派生类必须重载基类的同名虚函数, 否则编译不能通过 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 ConnetServer(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 CloseSockfd() override { if (_sockfd > defaultsockfd) ::close(_sockfd); } private: int _sockfd; }; }
#pragma once #include "Socket.hpp" #include <iostream> #include <pthread.h> #include <functional> // void 表示返回值为空, ()里面是参数 using func_t = std::function<void(Net_Work::Socket* sockp)>; 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->BulidListenSocketMethod(_port, Net_Work::backlog); } static void* ThreadRun(void* args) { pthread_detach(pthread_self()); ThreadData* td = static_cast<ThreadData*>(args); td->_this->_handler_request(td->_sockp); // 先回调, td->_sockp->CloseSockfd(); // 再关闭文件描述符 delete td->_sockp; delete td; } 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: " << newsock->GetSockFd() << " client info: " << peerip << ":" << peerport << std::endl; pthread_t tid; ThreadData* td = new ThreadData(this, newsock); pthread_create(&tid, nullptr, ThreadRun, td); } } ~TcpServer() { delete _listensocket; } private: int _port; Net_Work::Socket* _listensocket; func_t _handler_request; };
#include "Protocol.hpp" #include "Socket.hpp" #include <unistd.h> #include <iostream> #include <string> #include <memory> int main(int argc, char* argv[]) { if (argc != 3) { std::cout << "Usage: " << argv[0] << " serverip serverport" << std::endl; return 0; } std::string serverip = argv[1]; uint16_t serverport = std::stoi(argv[2]); Net_Work::Socket* s = new Net_Work::TcpSocket(); if (!s->BulidConnectSocketMethod(serverip, serverport)) { std::cerr << "connect " << serverip << ":" << serverport << "failed" << std::endl; } std::cout << "connect " << serverip << ":" << serverport << " success" << std::endl; std::unique_ptr<Factory> factory = std::make_unique<Factory>(); std::shared_ptr<Request> req = factory->BuildRequest(10, 20, '+'); while (true) { req->Inc(); send(s->GetSockFd(), &(*req), sizeof(*req), 0); sleep(1); } s->CloseSockfd(); return 0; }
工厂设计模式是一种创建型设计模式,它提供了一种灵活的方式来实例化和组织对象的创建。工厂设计模式是一种创建对象的软件设计模式,它通过一个公共接口或基类来创建对象,而无需暴露对象的具体实现。这种设计模式的主要作用是将对象的创建与使用分离,从而降低耦合度,使代码更易于理解和维护。
简易的工厂模式:一个请求类,一个回应类,一个工厂类。
#include <iostream> #include <memory> // 请求 class Request { public: Request() {} Request(int x, int y, char op) :_data_x(x), _data_y(y), _oper(op) {} private: // 约定好的 x _oper y int _data_x; int _data_y; char _oper; // + - * / % }; // 相应 class Response { public: Response() {} Response(int result, int code) :_result(result), _code(code) {} private: int _result; // 计算结果 int _code; // 运算状态 }; // 工厂模式 class Factory { public: std::shared_ptr<Request> BuildRequest() { std::shared_ptr<Request> req = std::make_shared<Request>(); return req; } std::shared_ptr<Request> BuildRequest(int x, int y, char op) { std::shared_ptr<Request> req = std::make_shared<Request>(x, y, op); return req; } std::shared_ptr<Response> BuildResponse() { std::shared_ptr<Response> resp = std::make_shared<Response>(); return resp; } std::shared_ptr<Response> BuildResponse(int result, int code) { std::shared_ptr<Response> resp = std::make_shared<Response>(result, code); return resp; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。