Zinx框架的高级用法

一、使用框架提供的实用类

zinx框架已经提供了常用的IO通道类-TCP。

阅读Tcp相关类的使用文档,将之前的3个案例用TCP的方式实现。

步骤:

  1. 创建Tcp数据通道类继承ZinxTcpData,重写GetInputNextStage函数,内容跟之前标准输入通道类的内容完全相同,但不直接构造对象。

  2. 创建Tcp工厂类,重写CreateTcpDataChannel函数,只构造一个Tcp数据通道对象,返回对象指针

  3. 创建ZinxTCPListen对象,指定好监听端口号和工厂对象。并将其添加到kernel中。

#include <zinx.h>
#include <ZinxTCP.h>
#include <iostream>
using namespace std;/*define class used to write stdout*/
class TestStdout:public Ichannel{
public:/*do nothing*/virtual bool Init(){}/*do nothing*/virtual bool ReadFd(std::string &_input){return false;}/*write to STDOUT directly*/virtual bool WriteFd(std::string &_output){cout << _output <<endl;return true;}/*do nothing*/virtual void Fini(){}/*return 1 which point to STDOUT*/virtual int GetFd(){return 1;}/*no impact*/virtual std::string GetChannelInfo(){return "test";}/*no next stage*/virtual AZinxHandler *GetInputNextStage(BytesMsg &_oInput){return NULL;}
} *poOut = new TestStdout();class Echo:public AZinxHandler
{
public:/*define echo action which is get string from input, and send out it via stdout channel object*/virtual IZinxMsg *InternelHandle(IZinxMsg &_oInput){GET_REF2DATA(BytesMsg, oBytes, _oInput);auto pchannel = ZinxKernel::Zinx_GetChannel_ByInfo(oBytes.szInfo);if (NULL != pchannel){ZinxKernel::Zinx_SendOut(oBytes.szData, *pchannel);}return NULL;}/*no next stage*/virtual AZinxHandler *GetNextHandler(IZinxMsg &_oNextMsg){return NULL;}
} *poEcho = new Echo();class ExitFramework:public AZinxHandler
{
public:virtual IZinxMsg *InternelHandle(IZinxMsg &_oInput){GET_REF2DATA(BytesMsg, oBytes, _oInput);if (oBytes.szData == "exit"){ZinxKernel::Zinx_Exit();return NULL;}return new BytesMsg(oBytes);}virtual AZinxHandler *GetNextHandler(IZinxMsg &_oNextMsg){return poEcho;}
} *poExit = new ExitFramework();class CmdHandler:public AZinxHandler
{
public:virtual IZinxMsg *InternelHandle(IZinxMsg &_oInput){GET_REF2DATA(BytesMsg, oBytes, _oInput);if (oBytes.szData == "close"){ZinxKernel::Zinx_Del_Channel(*poOut);return NULL;}else if (oBytes.szData == "open"){ZinxKernel::Zinx_Add_Channel(*poOut);return NULL;}return new BytesMsg(oBytes);}virtual AZinxHandler *GetNextHandler(IZinxMsg &_oNextMsg){GET_REF2DATA(BytesMsg, oBytes, _oNextMsg);if (oBytes.szData == "exit"){return poExit;}else{return poEcho;}}
} *poCmd = new CmdHandler();class TestStdin:public Ichannel{
public:/*do nothing*/virtual bool Init(){}virtual bool ReadFd(std::string &_input){cin>>_input;return true;}/*do nothing*/virtual bool WriteFd(std::string &_output){return false;}/*do nothing*/virtual void Fini(){}/*return 0 which point to STDIN*/virtual int GetFd(){return 0;}/*no impact*/virtual std::string GetChannelInfo(){return "test";}/*specify next stage is echo handler*/virtual AZinxHandler *GetInputNextStage(BytesMsg &_oInput){return poCmd;}
} *poIn = new TestStdin();class TestTcpData:public ZinxTcpData{
public:TestTcpData(int _fd):ZinxTcpData(_fd){}virtual AZinxHandler *GetInputNextStage(BytesMsg &_oInput){return poCmd;}
};class TestTcpFact:public IZinxTcpConnFact{virtual ZinxTcpData *CreateTcpDataChannel(int _fd){return new TestTcpData(_fd);}
};/*before main func called, three globle object was created before which were poOut point to a TestStdout object, poEcho point to a Echo object and poIn point to a TestStdin object.*/
int main()
{ZinxKernel::ZinxKernelInit();/*Add stdin and stdout channel to kernel*/ZinxKernel::Zinx_Add_Channel(*poIn);ZinxKernel::Zinx_Add_Channel(*poOut);auto tlc = new ZinxTCPListen(7766, new TestTcpFact());ZinxKernel::Zinx_Add_Channel(*tlc);/*start loop*/ZinxKernel::Zinx_Run();ZinxKernel::ZinxKernelFini();return 0;
}

二、编写一组实用类

需求:定时3秒钟,周期地向标准输出打印hello world

分析:

  • 怎么定时?是否可以通过fd反映超时?

  • 超时之后呢?直接输出hello world?(编写实用类要面向“客户”)

  • 定时的周期能否动态改?

思路:

  • 创建一个ZinxTimer类继承Ichannel类,这个类通过timerfd用来产生超时事件

  • 创建一个ZinxTimerDeliver类继承AZinxHandler类,这个类用来管理每次超时事件的分发和超时时间管理

  • 定义一个接口(全部方法都是纯虚函数的抽象类),提供纯虚函数用来处理超时事件

1.创建TimerOutProc抽象类

  • 仅提供两个纯虚函数,若有任务需要定时处理,则应该继承该类,重写这两个虚函数

  • Proc函数会在定时周期到期时被调用

  • GetTimerSec函数会在启动下一次定时任务时被调用,用来返回定时周期

class TimerOutProc {
public:virtual void Proc() = 0;virtual int GetTimerSec() = 0;virtual ~TimerOutProc();
};

2.创建ZinxTimerDeliver类

  • 需要重写的函数中最重要的是InternelHandle

  • 在InternelHandle中应该找出哪些TimerOutProc对象设定的时间到了,并执行其回调函数

  • 提供RegisterProcObject和UnRegisterProcObject函数用于注册TimerOutProc对象

  • 存储TimerOutProc对象时,要使用时间轮数据结构

  • 对于超时的管理应该是全局唯一的,所以需要单例模式

//定时器节点
struct WheelNode{int LastCount = -1;TimerOutProc *pProc = NULL;
};class ZinxTimerDeliver :public AZinxHandler
{static ZinxTimerDeliver m_single;//当前轮转刻度int m_cur_index = 0;//时间轮向量,每个坑中放一个multimap,multmap元素是圈数和定时器节点std::vector<std::multimap<int, WheelNode> > m_TimerWheel;
public:ZinxTimerDeliver();static ZinxTimerDeliver &GetInstance() {return m_single;}bool RegisterProcObject(TimerOutProc &_proc);void UnRegisterProcObject(TimerOutProc &_proc);// 通过 AZinxHandler 继承virtual IZinxMsg * InternelHandle(IZinxMsg & _oInput) override;virtual AZinxHandler * GetNextHandler(IZinxMsg & _oNextMsg) override;};bool ZinxTimerDeliver::RegisterProcObject( TimerOutProc & _proc)
{//计算圈数int last_count = _proc.GetTimerSec() / m_TimerWheel.size();//计算齿数int index = _proc.GetTimerSec() % m_TimerWheel.size();index += m_cur_index;index %= m_TimerWheel.size();//创建一个定时器节点存放圈数和定时器任务WheelNode tmp;tmp.LastCount = last_count;tmp.pProc = &_proc;//将定时器节点插入时间轮m_TimerWheel[index].insert(pair<int, WheelNode>(last_count, tmp));return true;
}void ZinxTimerDeliver::UnRegisterProcObject(TimerOutProc & _proc)
{//去注册就是遍历查找和删除for (auto single_map:m_TimerWheel){for (auto itr = single_map.begin(); itr != single_map.end(); itr++){if (itr->second.pProc == &_proc){single_map.erase(itr);return;}}}
}//处理超时的核心逻辑
IZinxMsg * ZinxTimerDeliver::InternelHandle(IZinxMsg & _oInput)
{uint64_t counts;GET_REF2DATA(BytesMsg, oBytes, _oInput);//获取当前超时的次数,一般是1,oBytes.szData.copy((char *)&counts, sizeof(counts), 0);for (int i = 0; i < counts; i++){//定义list存储超时的定时器节点,方便重新插入时间轮和后续回调list<WheelNode> wait_proc;for (auto itr = m_TimerWheel[m_cur_index].begin(); itr != m_TimerWheel[m_cur_index].end();){//遍历当前齿轮内的所有节点,将圈数减一itr->second.LastCount--;if (itr->second.LastCount <= 0){itr->second.LastCount = itr->first;wait_proc.push_back(itr->second);//删掉已经超时的定时器节点itr = m_TimerWheel[m_cur_index].erase(itr);}else{itr++;}}for (auto task : wait_proc){//调用超时处理函数task.pProc->Proc();//将本次遍历超时的所有定时器节点重新添加到时间轮中RegisterProcObject(*(task.pProc));}//刻度加一m_cur_index++;//刻度超了则转回来m_cur_index %= m_TimerWheel.size();}return nullptr;
}

3.创建ZinxTimer

  • 需要重写的函数最主要的是init和readfd

  • init函数中使用timerfd_create函数创建一个fd用于产生超时IO

  • Readfd函数中使用标准的read函数,消费每个超时IO。

  • 本类只负责产生1s的超时事件,这样可以让定时器更灵活

  • 产生1s的超时事件后,应该将该事件交给ZinxTimerDeliver处理

class ZinxTimer :public Ichannel
{
private:int m_fd = -1;
public:ZinxTimer();virtual ~ZinxTimer();// 通过 Ichannel 继承virtual bool Init() override;virtual bool ReadFd(std::string & _input) override;virtual bool WriteFd(std::string & _output) override;virtual void Fini() override;virtual int GetFd() override;virtual std::string GetChannelInfo() override;virtual AZinxHandler * GetInputNextStage(BytesMsg & _oInput) override;
};//在init函数中创建fd
bool ZinxTimer::Init()
{bool bRet = false;int timerfd = -1;//选用CLOCK_MONOTONIC类型的时钟,不会受系统时间修改影响timerfd = timerfd_create(CLOCK_MONOTONIC, 0);if (0 <= timerfd){//设置第一次超时时间和后续超时时间都是1秒struct itimerspec period = { {1,0}, {1,0} };if (0 == timerfd_settime(timerfd, 0, &period, NULL)){m_fd = timerfd;bRet = true;}else{close(timerfd);}}return bRet;
}bool ZinxTimer::ReadFd(std::string & _input)
{bool bRet = false;uint64_t over_times = 0;//调用read读取超时次数(大部分情况是1),将该64位数直接拷贝到输出参数字符串中(后续使用实再拷贝出来)if (sizeof(over_times) == read(m_fd, &over_times, sizeof(over_times))){_input.append((char *)&over_times, sizeof(over_times));bRet = true;}return bRet;
}
//返回ZinxTimerDeliver类的单例对象,表示超时事件由ZinxTimerDeliver处理
AZinxHandler * ZinxTimer::GetInputNextStage(BytesMsg & _oInput)
{return &ZinxTimerDeliver::GetInstance();
}

4.测试

  • 创建SpeakHello类继承TimerOutProc,用来输出“hello world”

  • 将SpeakHello对象注册到ZinxTimerDeliver中

  • 创建ZinxTimer对象并添加到kernel

class SpeakHello :public TimerOutProc {// 通过 TimerOutProc 继承virtual void Proc() override{string hello = "hello world";ZinxKernel::Zinx_SendOut(hello, *poOut);}virtual int GetTimerSec() override{return 3;}
};
int main()
{SpeakHello speak;ZinxTimerDeliver::GetInstance().RegisterProcObject(speak);ZinxKernel::Zinx_Add_Channel(*(new ZinxTimer()));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/761191.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot和Vue的大学生租房系统的设计与实现

今天要和大家聊的是一款今天要和大家聊的是一款基于SpringBoot和Vue的大学生租房系统的设计与实现。 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同…

【C++】弥补C语言的不足(②有默认参数的函数)

&#x1f33b;缺省参数 我们先来看一个简单地例子&#xff0c;对于在函数的定义中三个形参都给定默认值&#xff1a; #include <iostream> using namespace std; void fun(int a 10, int b 20, int c 30) {cout << "a " << a << endl;…

【考研数学】跟张宇,一看就会,一做就废,怎么办?

刚开始考研的时候都是这种情况&#xff0c;建议降低习题难度 刚开始就做1000题的都是勇士 1000题适合在强化阶段做&#xff0c;因为1000题中的题目&#xff0c;综合度高&#xff0c;需要做题者掌握比较多的解题技巧&#xff0c;而且对于计算能力要求也比较高。初学者肯定是不…

【OJ】动归练习一

个人主页 &#xff1a; zxctscl 如有转载请先通知 题目 1. 前言2. 1137第 N 个泰波那契数2.1 分析2.2 代码 3. 面试题 08.01. 三步问题3.1 分析3.2 代码 4. 746使用最小花费爬楼梯4.1 分析4.1.1 以i位置为终点4.1.2 以i位置为起点 4.2 代码4.2.1以i位置为终点4.2.2以i位置为起点…

深浅拷贝与初始化列表

一、深拷贝与浅拷贝 浅拷贝&#xff1a;简单的赋值拷贝操作 深拷贝&#xff1a;在堆区重新申请空间 由于栈上的数据先进后出&#xff0c;所以p2后释放&#xff0c;在执行析构代码时&#xff0c;新建的堆区数据就被释放&#xff0c;再当p1进行释放时&#xff0c;由于堆区数据…

【leetcode】67.二进制求和

前言&#xff1a;剑指offer刷题系列 问题&#xff1a; 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 示例&#xff1a; 输入&#xff1a;a "1010", b "1011" 输出&#xff1a;"10101"思路1&#xff1a; …

一命通关广度优先遍历

前言 在这篇文章之前&#xff0c;已对非线性结构遍历的另一种方法——深度优先遍历进行了讲解&#xff0c;其中很多概念词都是共用的。为了更好的阅读体验&#xff0c;最好先在掌握或起码了解dfs的基础上&#xff0c;再来阅读本文章&#xff0c;否则因为会有很多概念词看不明白…

如何修复WordPress网站媒体库上传文件失败的问题

公司最近推出了一系列新产品&#xff0c;为了更新网站的视频和图片&#xff0c;我们需要将它们上传至网站媒体库。然而&#xff0c;在上传视频时&#xff0c;我们却遇到了一些问题。系统提示说&#xff0c;我们尝试上传的视频文件大小超出了站点的最大上传限制。尽管我们的视频…

计算机网络:性能指标

计算机网络&#xff1a;性能指标 速率带宽吞吐量时延时延带宽积往返时间利用率丢包率 本博客介绍计算机网络的性能指标&#xff0c;我们可以从不同的方面来度量计算机网络的性能。常用的计算机网络性能指标有以下 8 个&#xff0c;他们是&#xff1a;速率、带宽、吞吐量、时延、…

NVIDIA NCCL 源码学习(十三)- IB SHARP

背景 之前我们看到了基于ring和tree的两种allreduce算法&#xff0c;对于ring allreduce&#xff0c;一块数据在reduce scatter阶段需要经过所有的rank&#xff0c;allgather阶段又需要经过所有rank&#xff1b;对于tree allreduce&#xff0c;一块数据数据在reduce阶段要上行…

智慧交通运维合集:基于图扑数字孪生技术的解决方案

城市交通作为城市与区域交通体系的核心&#xff0c;其完善程度和发展水平是评价城市现代化水准的关键指标之一。 城市交通数字孪生技术正在成为城市交通管理的关键工具&#xff0c;支持系统的高效运行和安全保障。随着互联网、大数据和人工智能技术的进步&#xff0c;城市交通…

LLM—Transformer作用及信息流

一、Transformer的作用 Transformer架构的精髓在于其创新性地采用了编码器与解码器的堆叠设计&#xff0c;这一设计巧妙地融合了多头自注意力机制&#xff08;Multi-Head Attention&#xff09;和位置前馈网络&#xff08;Position-wise Feed Forward Network&#xff09;两大核…

【Memcached】springBoot 集成 memcached 两万字长文带你认识memcached

目录 一、 memcached 介绍1.1 简介1.2 特性1.3 优点1.4 缺点1.5 实现原理1.6 适用场景1.7 不适用场景1.8 与 Redis 比较相同点1.9 与 Redis 比较不同点 二、对 java 的支持2.1 Memcached-java-client 客户端2.2 Spymemcached 客户端2.3 XMemcached 客户端 三、下载安装3.1 wind…

美易官方:美股维持涨势,三大股指再创新高

在今日的早盘交易中&#xff0c;美股市场继续维持其涨势&#xff0c;三大股指再次刷新历史纪录。市场信心受到一系列积极经济数据的支撑&#xff0c;投资者对未来的经济增长和企业盈利保持乐观态度。 首先&#xff0c;让我们来看一下道琼斯工业平均指数的表现。该指数在早盘交易…

[实践经验]: visual studio code 实用技巧

目录 editor rulers 这里主要总结一些常用的VScode技巧&#xff0c;不定时更新… editor rulers 设置 -> 搜索 editor.rulers -> edit in settings.json "editor.rulers": [{"column": 80,"color": "#ff00FF"},]效果如图

【概念验证(POC):技术项目开发的关键一步】

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

Python脚本:用py处理PDF的五大功能

一、代码 【第三方库】3个 【Py版本】3.9 【使用前提】关闭所有的word文档 import os from datetime import datetime from docx2pdf import convert from pdf2docx import parse from PyPDF2 import PdfMerger from PyPDF2 import PdfReader,PdfWriter#将文件夹中的所有Wo…

Linux:网络的初步认知

文章目录 网络的认知如何理解协议网络分层OSI模型TCP/IP五层(或四层)模型网络传输的基本流程协议的参与局域网通信原理 本篇将会引入到网络的话题 网络的认知 第一个问题是&#xff0c;网卡是文件吗&#xff1f;答案是显然的&#xff0c;在Linux下一切皆文件&#xff0c;基于…

Trait与生命周期

原文链接&#xff1a;(*∇&#xff40;*) 咦,又好了~ Rust – xiaocr_bloghttp://www.xiaocr.fun/index.php/2024/03/18/trait%E4%B8%8E%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/ 目录 Trait 定义trait 默认实现 trait作为参数 Trait Bound语法 通过指定多个 trait bound …

opengl日记12-opengl坐标系统

文章目录 环境代码CMakeLists.txtvertexShaderSource.vsmain.cpp 总结 环境 系统&#xff1a;ubuntu20.04opengl版本&#xff1a;4.6glfw版本&#xff1a;3.3glad版本&#xff1a;4.6cmake版本&#xff1a;3.16.3gcc版本&#xff1a;10.3.0 在<opengl学习日记11-opengl的t…