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

TCP网络事件模型的封装1.0

TCP网络模型的封装

最近学习了TCP网络模型的封装,其中运用的封装技术个人感觉有点绕

在反复读代码、做思维导图下初步理解了这套封装模型,不禁感叹原来代码还能这样写?神奇!

为此将源码分享出来并将流程图画出,方便理解和复习

PS:下列思维导图仅代表个人理解,如有误恳请指出纠正

模型继承关系图

要理解该模型,我认为首先要画图理解类的继承关系,下面是我画的一个简单关系图
在这里插入图片描述

模型流程图

下面是我画的该模型的大致流程图,仅供参考,有误恳请指出
在这里插入图片描述

具体代码实现

EventLoop.hpp

#ifndef _EVENTLOOP_H_
#define _EVENTLOOP_H_#include <list>
#include <WinSock2.h>enum class E_Event_Type
{Recv,Send,
};class IEventCallback
{
public:virtual void OnNetEvent(E_Event_Type e) = 0;virtual void OnClose() = 0;
};struct sSelectEvent
{SOCKET sock;IEventCallback* event;
};class EventLoop
{
private:std::list<sSelectEvent*> _events;std::list<sSelectEvent*> _delEventCaches;public:void LoopOnce();void AddEvent(sSelectEvent* e){_events.push_back(e);}void DelEvent(sSelectEvent* e);
};
#endif

EventLoop.cpp

#include "EventLoop.hpp"void EventLoop::LoopOnce()
{fd_set reads;FD_ZERO(&reads);do{auto begin = _events.begin();auto end = _events.end();for (; begin != end; ++begin)FD_SET((*begin)->sock, &reads);//(*begin)->event->NeedWrite()} while (false);int nSeclect = select(0, &reads, nullptr, nullptr, nullptr);if (0 == nSeclect)return;if (nSeclect < 0)return;do{auto begin = _events.begin();auto end = _events.end();for (; begin != end; ++begin){if (FD_ISSET((*begin)->sock, &reads)){(*begin)->event->OnNetEvent(E_Event_Type::Recv);}}} while (false);do{auto begin = _delEventCaches.begin();auto end = _delEventCaches.end();for (; begin != end; ++begin){sSelectEvent* p = *begin;_events.remove_if([p](sSelectEvent* a){return a == p;});p->event->OnClose();}_delEventCaches.clear();} while (false);}void EventLoop::DelEvent(sSelectEvent* e)
{_delEventCaches.push_back(e);
}

TcpListen.hpp

#ifndef _TCPLISTEN_H_
#define _TCPLISTEN_H_
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include "EventLoop.hpp"
#include <WinSock2.h>
#include <iostream>
#include <functional>
class TcpSocket;
class TcpListen :public IEventCallback
{
protected:SOCKET _sock;sSelectEvent _event;EventLoop* _loop;std::function<TcpSocket* ()> _sockCB;
public:TcpListen();void Init(EventLoop* loop, std::function<TcpSocket* ()> sockCB){_loop = loop; _sockCB = sockCB;}bool Listen(unsigned short port, const char* const ip = "0.0.0.0");// 通过 IEventCallback 继承virtual void OnNetEvent(E_Event_Type e) override;virtual void OnClose() override;
public:virtual void OnAccpet(TcpSocket* sock) = 0;};
#endif

TcpListen.cpp

#include "TcpListen.h"
#include "TcpSocket.h"
TcpListen::TcpListen()
{_event.event = this;_sock = _event.sock = INVALID_SOCKET;_loop = nullptr;
}bool TcpListen::Listen(unsigned short port, const char* const ip)
{_sock = socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == _sock){std::cout << "create SOCKET fail!\n" << std::endl;return false;}std::cout << "1.create SOCKET OK!\n" << std::endl;// 2.绑定IP和端口
//  bind(SOCKET,绑定的IP端口结构体,结构体大小)SOCKADDR_IN serverAddr;serverAddr.sin_family = AF_INET;//SOCKADDR_IN6*serverAddr.sin_port = htons(port);// 127.0.0.1 本机回环地址// 0.0.0.0  绑定所有IPserverAddr.sin_addr.s_addr = inet_addr(ip);//SOCKADDR_IN6 serverAddr6;if (SOCKET_ERROR== bind(_sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr))){std::cout << "bind SOCKET fail!\n" << std::endl;return false;}std::cout << "2.bind SOCKET OK!\n" << std::endl;listen(_sock, 5);std::cout << "3.listen SOCKET OK!\n" << std::endl;_event.sock = _sock;_loop->AddEvent(&_event);return true;
}void TcpListen::OnNetEvent(E_Event_Type e)
{SOCKADDR_IN clientAddr;int addrlen = sizeof(SOCKADDR_IN);SOCKET clientSock = accept(_sock, (SOCKADDR*)&clientAddr, &addrlen);if (INVALID_SOCKET == clientSock){std::cout << "4.ACCEPT ERROR!!\n" << std::endl;return;}std::cout << "4.ACCEPT ip:" << inet_ntoa(clientAddr.sin_addr)<< "  Port:" << ntohs(clientAddr.sin_port) << "   " << clientSock<< std::endl;TcpSocket* sock = _sockCB();sock->OnAccept(clientSock, &clientAddr);OnAccpet(sock);}void TcpListen::OnClose()
{
}

TcpSocket.hpp

#ifndef _TCPSOCKET_H_
#define _TCPSOCKET_H_
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include "EventLoop.hpp"const unsigned int RECV_MAX_BUF = 4096 * 2;class TcpSocket :public IEventCallback
{
private:SOCKET _sock;SOCKADDR_IN _addr;sSelectEvent _event;EventLoop* _loop;char _recvBuff[RECV_MAX_BUF];int _recvLen;bool _bClose;
public:TcpSocket();virtual ~TcpSocket();void Init(EventLoop* loop);void OnAccept(SOCKET sock, SOCKADDR_IN* addr);void Close();public:// 通过 IEventCallback 继承virtual void OnNetEvent(E_Event_Type e) override;virtual void OnClose() override;public:virtual int OnNetMsg(const char* const msg, int msgLen) = 0;void Send(const char* msg, int msgLen);};#endif

TcpSocket.cpp

#include "TcpSocket.h"TcpSocket::TcpSocket()
{_sock = _event.sock = INVALID_SOCKET;_event.event = this;_recvLen = 0;_bClose = false;
}TcpSocket::~TcpSocket()
{
}void TcpSocket::Init(EventLoop* loop)
{_loop = loop;_loop->AddEvent(&_event);
}void TcpSocket::OnAccept(SOCKET sock, SOCKADDR_IN* addr)
{_sock = sock;_event.sock = sock;memcpy(&_addr, addr, sizeof(addr));
}void TcpSocket::Close()
{if (_bClose) return;_bClose = true;_loop->DelEvent(&_event);
}void TcpSocket::OnNetEvent(E_Event_Type e)
{if (E_Event_Type::Recv == e){int nRecv = recv(_sock, _recvBuff + _recvLen, RECV_MAX_BUF - _recvLen, 0);if (nRecv <= 0){Close();return;}_recvLen += nRecv;while (_recvLen != 0){int nRet = OnNetMsg(_recvBuff, _recvLen);if (nRet <= 0)break;_recvLen -= nRet;for (int i = 0; i < _recvLen; ++i){_recvBuff[i] = _recvBuff[i + nRet];}}if (_recvLen == RECV_MAX_BUF) Close();}
}void TcpSocket::OnClose()
{closesocket(_sock);delete this;
}void TcpSocket::Send(const char* msg, int msgLen)
{send(_sock, msg, msgLen, 0);
}

EasyTcpServer.cpp

#define  _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>#include <WinSock2.h>
#pragma comment(lib,"ws2_32")
#include <vector>#include "TcpListen.h"
#include "TcpSocket.h"class EasyTcpClient :public TcpSocket
{
public:// 通过 TcpSocket 继承virtual int OnNetMsg(const char* const msg, int msgLen) override{std::cout << msgLen << "接受客户端数据:" << msg << std::endl;return msgLen;}
};class EasyTcpServer :public TcpListen
{
public:void OnAccpet(TcpSocket* sock) override{//sock->Init(_loop)sock->Init(_loop);std::cout << "客户端连接" << std::endl;}};int main()
{// 加载网络环境WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);EventLoop loop;EasyTcpServer listen;listen.Init(&loop, []()->TcpSocket*{return new EasyTcpClient;});listen.Listen(7890);while (true){loop.LoopOnce();}return 0;
}

最后

void OnAccpet(TcpSocket* sock) override
{//sock->Init(_loop)sock->Init(_loop);std::cout << "客户端连接" << std::endl;
}

};

int main()
{
// 加载网络环境
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);

EventLoop loop;EasyTcpServer listen;listen.Init(&loop, []()->TcpSocket*{return new EasyTcpClient;});listen.Listen(7890);while (true)
{loop.LoopOnce();
}return 0;

}

# 最后代码经供参考,如有疑问或者代码有问题欢迎提出

相关文章:

TCP网络事件模型的封装1.0

TCP网络模型的封装 最近学习了TCP网络模型的封装&#xff0c;其中运用的封装技术个人感觉有点绕 在反复读代码、做思维导图下初步理解了这套封装模型&#xff0c;不禁感叹原来代码还能这样写&#xff1f;神奇&#xff01; 为此将源码分享出来并将流程图画出&#xff0c;方便…...

NC271.二叉搜索树的后序遍历序列

文章目录一、题目描述二、示例三、主要思路一、题目描述 输入一个整数数组&#xff0c;判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回 true ,否则返回 false 。假设输入的数组的任意两个数字都互不相同。 提示&#xff1a; 1.二叉搜索树是指父亲节点大于左子树中…...

研究fastdds v2.8.0 1之 基础模块

阅读 dds 协议 1.4 版本 &#xff0c; 结合fastdds 2.8 的代码理解dds。 Entity 理解 DCPS基础设施模块由以下类组成&#xff1a; Entity DomainEntity QosPolicy Listener Status WaitSet Condition GuardCondition StatusCondition1、Entity 是所有DCPS 对象的基础类 virt…...

ElasticSearch系列 - SpringBoot整合ES:精确值查询 term

文章目录01. ElasticSearch term 查询&#xff1f;02. ElasticSearch term 查询数值型数据&#xff1f;03. ElasticSearch term 查询字符串类型数据&#xff1f;04. ElasticSearch term 查询日期型数据&#xff1f;05. ElasticSearch term 查询日期型数据的注意事项&#xff1f…...

关于async/await、promise和setTimeout执行顺序

关于async/await、promise和setTimeout执行顺序 async function async1() {console.log(async1 start);await async2();console.log(asnyc1 end); } async function async2() {console.log(async2); } console.log(script start); setTimeout(() > {console.log(setTimeOut…...

2023-03-31:如何计算字符串中不同的非空回文子序列个数?

2023-03-31&#xff1a;给定一个字符串 s&#xff0c;返回 s 中不同的非空 回文子序列 个数&#xff0c; 通过从 s 中删除 0 个或多个字符来获得子序列。 如果一个字符序列与它反转后的字符序列一致&#xff0c;那么它是 回文字符序列。 如果有某个 i , 满足 ai ! bi &#xff…...

D. The Number of Imposters(二分图染色)

Problem - D - Codeforces Theofanis开始玩名为“Among them”的新网络游戏。然而&#xff0c;他总是和塞浦路斯球员一起踢球&#xff0c;他们都有一个相同的名字:“安德烈亚斯”(塞浦路斯最常见的名字)。在每个游戏中&#xff0c;Theofanis和n个其他玩家一起玩。因为它们都有相…...

图片太大怎么改小kb?简单的图片压缩方法分享

平时当我们在朋友圈分享一些有趣的照片或者使用图片素材进行上传的时候&#xff0c;经常遇到图片大小kb超出平台限制的情况&#xff0c;这时就无法正常上传了&#xff0c;遇到这种情况我们就需要想办法降低图片大小kb&#xff0c;那么有什么办法能够压缩图片大小呢&#xff1f;…...

【python-leecode刷题】动态规划类问题----以53. 最大子数组和为例

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于海外某世界知名高校就读计算机相关专业。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。…...

Idea常用快捷键设置

设置来源于尚硅谷宋红康老师 第1组&#xff1a;通用型 说明 快捷键 复制代码-copy ctrl c 粘贴-paste ctrl v 剪切-cut ctrl x 撤销-undo ctrl z 反撤销-redo ctrl shift z 保存-save all ctrl s 全选-select all ctrl a 第2组&#xff1a;提高编写速度&#xff08;上…...

【新2023Q2模拟题JAVA】华为OD机试 - 分苹果

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:分苹果 题目 AB两个人把苹果…...

【博学谷学习记录】超强总结,用心分享丨人工智能 自然语言处理 BERT、GPT、ELMO对比学习简记

目录三模型架构BERTGPTELMO三者差异点三模型架构 BERT 优点 在11个NLP任务上取得SOAT成绩.利用了Transformer的并行化能力以及长语句捕捉语义依赖和结构依赖.BERT实现了双向Transformer并为后续的微调任务留出足够的空间. 缺点 BERT模型太大, 太慢.BERT模型中的中文模型是以…...

【嵌入式Bluetooth应用开发笔记】第四篇:初探蓝牙HOST及应用开发(持续更新ing)

概念 蓝牙HOST(Bluetooth Host)是指能够连接到其他蓝牙设备并控制它们的设备。在蓝牙技术中,通常有两种类型的设备:蓝牙HOST和蓝牙SLAVE。蓝牙HOST通常是指拥有控制权的设备,它可以主动连接其他蓝牙设备并向其发送命令。相反,蓝牙SLAVE则是指被动连接的设备,它接受来自…...

GORM 基础 -- CRUD 接口

1、Create 1.1 创建纪录 user : User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}result : db.Create(&user) // pass pointer of data to Createuser.ID // 回填插入数据的主键 result.Error // 返回的 error 信息 result.RowsAffect…...

为什么0代码自动化测试越来越受欢迎?一文2000字解析

目录 01、什么是零代码自动化测试 02、为什么零代码自动化测试越来越受欢迎 03、有代码和零代码自动化有什么区别 04、零代码自动化测试可以帮助你做什么 05、零代码自动化测试方法&#xff1a;NLP&#xff08;自然语言处理&#xff09; 06、为什么我们需要零代码自动化测…...

cleanmymac最新2023版 mac清理软件CleanMyMac X4.12.5 中文版功能介绍

CleanMyMac X4.12.5 中文版只需两个简单步骤就可以把系统里那些乱七八糟的无用文件统统清理掉&#xff0c;节省宝贵的磁盘空间。cleanmymac x个人认为X代表界面上的最大升级&#xff0c;功能方面有更多增加&#xff0c;与最新macOS系统更加兼容&#xff0c;流畅地与系统性能更加…...

pyhon部署注意事项

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…...

宣城x移动云,打造“城市级物联感知平台”

随着新一代信息技术与城市现代化的深度融合&#xff0c;智慧城市建设的重要性也愈发凸显。而在智慧城市建设中&#xff0c;物联网感知体系扮演着中枢神经系统的角色。 安徽宣城紧抓长三角城市群一体化发展机遇&#xff0c;为构建“数字宣城”建设发展新模式&#xff0c;携手移…...

英伟达Jetson NX套件刷机,配置Ubuntu20。

0. 前言 人并没有眼见得那么光鲜亮丽&#xff0c;博客也是。 今天推荐一本书《一百个人的十年》&#xff0c;没错就是我们的那十年&#xff08;60年代&#xff09;。写得很真实&#xff0c;牛棚猪圈&#xff0c;确实如此。 1. SdkManager安装 官网下载。 打开终端 执行命令sud…...

Vue计算属性

计算属性 ​ 计算属性的重点突出在属性两个字上(属性是名词)&#xff0c;首先它是个属性其次这个属性有计算的能力(计算是动词)&#xff0c;这里的计算就是个函数;简单点说&#xff0c;它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性)&#xff0c;仅此而已…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...