使用模板方法設計模式封裝 socket 套接字并實現Tcp服務器和客戶端 簡單工廠模式設計

文章目錄

  • 使用模板方法設計模式封裝套接字
  • 使用封裝后的套接字實現Tcp服務器和客戶端
    • 實現Tcp服務器
    • 實現Tcp客戶端
  • 工廠模式

在這里插入圖片描述

使用模板方法設計模式封裝套接字

可以使用模塊方法設計模式來設計套接字 socket 的封裝

模板方法(Template Method)設計模式是一種行為設計模式,它在一個方法中定義了一個算法的骨架,并允許子類為一個或多個步驟提供實現。模板方法使得子類可以不改變一個算法的結構即可重新定義該算法的某些特定步驟。

  1. 抽象類(Abstract Class):定義了一個或多個抽象操作,以及一個模板方法。這個模板方法調用了一個或多個抽象操作。
  2. 具體子類(Concrete Subclass):實現抽象類中的抽象操作,從而完成算法中特定步驟的具體實現。

抽象類定義了一個模板方法,這個方法通常包含對具體方法的調用,抽象類還定義了一些抽象方法,這些方法會在模板方法中被調用,但具體的實現由子類來提供(抽象類,也就是父類中,將這些方法都設置為純虛函數,子類要重寫純虛函數),子類通過繼承抽象類并提供抽象方法的實現,從而可以自定義模板方法中的某些步驟,當模板方法被調用時,它會按照定義的順序依次調用抽象類中的抽象方法和具體方法。

#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;elsereturn false;}int GetSockFd() override{return _sockfd;}void SetSockFd(int sockfd) override{_sockfd = sockfd;}void CloseSockfd() override{if (_sockfd > defaultsockfd)::close(_sockfd);}private:int _sockfd;};
}

使用封裝后的套接字實現Tcp服務器和客戶端

實現Tcp服務器

#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;
};

實現Tcp客戶端

#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;
}

工廠模式

工廠設計模式是一種創建型設計模式,它提供了一種靈活的方式來實例化和組織對象的創建。工廠設計模式是一種創建對象的軟件設計模式,它通過一個公共接口或基類來創建對象,而無需暴露對象的具體實現。這種設計模式的主要作用是將對象的創建與使用分離,從而降低耦合度,使代碼更易于理解和維護。

  • 抽象產品(Abstract Product):定義了一個產品的接口或抽象類,它描述了產品的共同屬性和方法。
  • 具體產品(Concrete Product):實現了抽象產品接口或繼承自抽象產品類的具體類,代表了具體的對象。
  • 工廠類(Factory Class):負責創建具體產品的實例,它通常包含一個工廠方法,用于創建產品對象。
    優點:
  1. 解耦:將對象的創建與使用分離,降低了客戶端與具體產品之間的耦合度。
  2. 靈活性和可擴展性:通過引入抽象層,可以輕松地創建新的具體產品類,而無需修改客戶端代碼。
  3. 代碼復用:通過封裝對象的創建過程,可以在多個客戶端之間復用相同的創建邏輯。

簡易的工廠模式:一個請求類,一個回應類,一個工廠類。

#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 yint _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;}
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/36967.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/36967.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/36967.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【深度學習】深度學習基礎

李宏毅深度學習筆記 局部極小值與鞍點 鞍點其實就是梯度是零且區別于局部極小值和局部極大值的點。 鞍點的叫法是因為其形狀像馬鞍。鞍點的梯度為零&#xff0c;但它不是局部極小值。我們把梯度為零的點統稱為臨界點&#xff08;critical point&#xff09;。損失沒有辦法再下…

使用Flink CDC實現 Oracle數據庫數據同步(非SQL)

文章目錄 前言一、開啟歸檔日志二、創建flinkcdc專屬用戶2.1 對于Oracle 非CDB數據庫&#xff0c;執行如下sql2.2 對于Oracle CDB數據庫&#xff0c;執行如下sql 三、指定oracle表、庫級啟用四、使用flink-connector-oracle-cdc實現數據庫同步4.1 引入pom依賴4.1 Java主代碼4.1…

Docker Desktop 簡易操作指南 (Windows, macOS, Linux)

1. 下載最新版本 Docker Desktop https://www.docker.com/products/docker-desktop/ 2.啟動 Docker Desktop 3.常用命令&#xff08;在 cmd 或 Terminal 中執行&#xff09; #列出所有鏡像&#xff08;Images&#xff09; docker images #列出所有容器&#xff08;Containers&…

OpenSSL/3.3.0: error:0A00018A:SSL routines::dh key too small

php curl解決辦法: curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, ‘DEFAULTSECLEVEL1’); python 解決辦法: from twisted.internet.ssl import AcceptableCiphers from scrapy.core.downloader import contextfactory contextfactory.DEFAULT_CIPHERS AcceptableCiphers.from…

CSS 核心知識點 - grid

思維導圖 參考網址: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_grid_layout 一、什么是 grid&#xff1f; CSS Grid布局是在CSS3規范中引入的一種新的布局方式&#xff0c;旨在解決傳統布局方法&#xff08;如浮動、定位、表格布局&#xff09;存在的許多問題。C…

Spring Boot 集成 MyBatis-Plus 總結

Spring Boot 集成 MyBatis-Plus 總結 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在Java開發中&#xff0c;Spring Boot以其簡潔和高效的特點&#xff0c;…

Oh My Zsh Git 插件

以下是一些常見的別名和它們對應的 Git 命令&#xff1a; g: gitga: git addgaa: git add --allgapa: git add --patchgau: git add --updategb: git branchgba: git branch -agbd: git branch -dgbda: git branch --no-color --merged | command grep -vE “^(||*|\s*(main|m…

第十九站:Java鈦藍——區塊鏈技術的新探索

在區塊鏈技術的新探索中&#xff0c;Java作為一門成熟的編程語言&#xff0c;正在通過Hyperledger Fabric和Web3j等技術實現其在區塊鏈領域的應用。以下是對這些技術的簡要介紹和如何使用Java源代碼與它們進行交互的講解。 Hyperledger Fabric Hyperledger Fabric是一個由Lin…

React.js 全面解析:從基礎到實戰案例

引言&#xff1a; React.js&#xff0c;由Facebook推出并維護的開源JavaScript庫&#xff0c;以其組件化思想、虛擬DOM技術和聲明式編程風格&#xff0c;成為構建用戶界面的首選工具之一。本文將系統性地介紹React的基礎概念、核心特性&#xff0c;并通過實際案例展示基礎屬性…

DataWhale-吃瓜教程學習筆記(四)

學習視頻&#xff1a;第3章-二分類線性判別分析_嗶哩嗶哩_bilibili 西瓜書對應章節&#xff1a; 3.4 文章目錄 - 算法原理- 損失函數推導-- 異類樣本中心盡可能遠-- 同類樣本方差盡可能小-- 綜合 知識點補充 - 二范數二范數&#xff08;2-norm&#xff09;詳解定義幾何意義性質…

vue3中省市區聯動在同一個el-form-item中咋么設置rules驗證都不為空的效果

在開發中出現如下情況&#xff0c;在同一個el-form-item設置了省市區三級聯動的效果 <el-form-item label"地區" prop"extraProperties.Province"><el-row :gutter"20"><el-col :span"12"><el-select v-model&qu…

OpenHarmony開發實戰:HDF驅動開發流程

概述 HDF&#xff08;Hardware Driver Foundation&#xff09;驅動框架&#xff0c;為驅動開發者提供驅動框架能力&#xff0c;包括驅動加載、驅動服務管理、驅動消息機制和配置管理。并以組件化驅動模型作為核心設計思路&#xff0c;讓驅動開發和部署更加規范&#xff0c;旨在…

Unity3D Excel表格數據處理模塊詳解

一、引言 在Unity3D開發中&#xff0c;我們經常需要處理大量的數據&#xff0c;這些數據可能是游戲配置、角色屬性、道具信息等。Excel表格作為一種常見的數據存儲方式&#xff0c;具有結構清晰、易于編輯的特點&#xff0c;因此被廣泛應用于游戲開發中。本文將詳細介紹如何在…

四川赤橙宏海商務信息咨詢有限公司抖音開店靠譜嗎?

在數字化浪潮席卷全球的今天&#xff0c;電商行業正以前所未有的速度發展。而在這個大潮中&#xff0c;四川赤橙宏海商務信息咨詢有限公司憑借其專業的團隊和前瞻性的戰略眼光&#xff0c;專注于抖音電商服務&#xff0c;為廣大商家提供了一站式解決方案&#xff0c;成為了行業…

面經-常用框架

1.Spring 1.1什么是Spring框架&#xff1f; Spring 是?種輕量級開發框架&#xff0c;旨在提?開發?員的開發效率以及系統的可維護性。 Spring 的 6 個特征:核?技術&#xff0c;測試&#xff0c;數據訪問&#xff0c;Web?持&#xff0c;集成&#xff0c;語? 1.2列舉?些重…

Ubuntu20.04安裝LibTorch并完成高斯濺射環境搭建

0. 簡介 最近受到優刻得的使用邀請&#xff0c;正好解決了我在大模型和自動駕駛行業對GPU的使用需求。UCloud云計算旗下的Compshare的GPU算力云平臺。他們提供高性價比的4090 GPU&#xff0c;按時收費每卡2.6元&#xff0c;月卡只需要1.7元每小時&#xff0c;并附帶200G的免費…

接口自動化測試-項目實戰

什么是接口自動化測試&#xff1a;使用工具或代碼代替人對接口進行測試 測試項目結構&#xff08;python包&#xff09; 1、接口api包 2、script:業務腳本 3、data:數據 4、config.py :配置文件 5、reporter:報告 錯誤問題&#xff1a; 1、未打印任何東西。添加pip ins…

走馬燈封裝

走馬燈功能需求&#xff1a; 支持定時切換&#xff1b;支持左右按鈕切換&#xff08;根據鼠標是否在切換組件內展示和隱藏左右切換按鈕&#xff09;&#xff1b;支持底部標識切換&#xff1b; 走馬燈 完整代碼如下&#xff1a; /*** class 走馬燈*/import react, { Compone…

C語言 指針——緩沖區溢出與緩沖區溢出攻擊

目錄 緩沖區溢出攻擊 緩沖區溢出攻擊實例 字符串的安全輸入方法?編輯 防止緩沖區溢出的兩個要點 緩沖區溢出攻擊 網絡黑客常針對系統和程序自身存在的漏洞&#xff0c;編寫相應的攻擊程序 ? 對緩沖區溢出漏洞的攻擊 —— 最常見 ? 幾乎占到了網絡攻擊次數的一半以上…

Android (已解決)Gradle 編譯失敗 Unsupported class file major version 61

文章目錄 一、報錯原因二、解決方法 一、報錯原因 新版本的 Android Studio 默認使用的是 Java 17 LTS&#xff0c;而這個歷史項目的 Gradle 版本很低&#xff0c;不支持高版本的 Java。 具體原因&#xff1a;Java 17 (major version 61) 編譯的 class 文件&#xff0c;如果在…