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

高级IO——React服务器简单实现

3.4Reactor服务器实现

1.connect封装

​ 每一个连接都要有一个文件描述符和输入输出缓冲区,还有读、写、异常处理的回调方法;

​ 还包括指向服务器的回指指针;

class connection;
class tcpserver;using func_t = std::function<void(std::shared_ptr<connection>)>;
class connection
{
public:connection() {}~connection() {}private:int sockfd_;            // 文件描述符std::string inbuffer_;  // 输入缓冲区,string缺陷就是不可以处理二进制流std::string outbuffer_; // 输出缓冲区func_t rcb_;            // 设置回调函数,将IO方法交给上层func_t wcb_;            // 写回调func_t ecb_;            // 异常回调std::shared_ptr<tcpserver> tsvr_; // 添加一个回指指针
};

2.tcpserver封装

​ 设置epoll对象(用来将连接的属性设置进内核),监听套接字,文件描述符和连接的映射,并用智能指针管理;

​ 设置nocopy对象不允许服务器拷贝;

​ 通过使用EPOLLET事件实现ET工作模式,并且非阻塞文件描述符;

​ 使用addconnection函数实现管理所有的文件描述符;

​ epoll_event结构体数组来获取就绪的事件;

#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
#include <fcntl.h>
#include <unistd.h>
#include "Socket.hpp"
#include "Log.hpp"
#include "nocopy.hpp"
#include "epoll.hpp"
#include "Socket.hpp"
#include "comm.hpp"class connection;
class tcpserver;
uint32_t event_in = (EPOLLIN | EPOLLET);
uint32_t event_out = (EPOLLOUT | EPOLLET);
using func_t = std::function<void(std::shared_ptr<connection>)>;
static const uint16_t defaultport = 8080;class connection
{
public:connection(int sockfd, std::shared_ptr<tcpserver> tsvr) : sockfd_(sockfd), tsvr_(tsvr) {}~connection() {}public:void sethandler(func_t rcb, func_t wcb, func_t ecb){rcb_ = rcb;wcb_ = wcb;ecb_ = ecb;}int Fd(){return sockfd_;}private:int sockfd_;            // 文件描述符std::string inbuffer_;  // 输入缓冲区,string缺陷就是不可以处理二进制流std::string outbuffer_; // 输出缓冲区
public:func_t rcb_ = nullptr; // 设置回调函数,将IO方法交给上层func_t wcb_ = nullptr; // 写回调func_t ecb_ = nullptr; // 异常回调std::shared_ptr<tcpserver> tsvr_; // 添加一个回指指针
};class tcpserver : public nocopy
{static const int num = 64;public:tcpserver(uint16_t port = defaultport): ep_ptr_(new epoll()), listensock_ptr_(new Sock()), port_(port), quit_(true){}~tcpserver(){listensock_ptr_->Close();}public:void init(){listensock_ptr_->Socket();setnonblock(listensock_ptr_->Fd());listensock_ptr_->Bind(port_);listensock_ptr_->Listen();lg(Info, "create listen socket success, listensockfd: %d", listensock_ptr_->Fd());addconnection(listensock_ptr_->Fd(), event_in, std::bind(&tcpserver::Accept, this, std::placeholders::_1), nullptr, nullptr);}void addconnection(int sockfd, uint32_t event, func_t rcb, func_t wcb, func_t ecb){// 1.建立sockfd对应connection对象std::shared_ptr<connection> c_ptr = std::make_shared<connection>(sockfd, std::shared_ptr<tcpserver>(this));c_ptr->sethandler(rcb, wcb, ecb);// 2.将connection添加到映射表中connections_[sockfd] = c_ptr;// 3.将fd与事件添加到内核中ep_ptr_->Update(EPOLL_CTL_ADD, sockfd, event);lg(Debug, "add a new connection, sockfd: %d", sockfd);}void Accept(std::shared_ptr<connection> connection_ptr){while (true){sockaddr_in client;socklen_t len = sizeof(client);int sockfd = accept(connection_ptr->Fd(), (sockaddr *)&client, &len);if (sockfd > 0){uint16_t clientport = ntohs(client.sin_port);char ipstr[64];inet_ntop(AF_INET, &client.sin_addr, ipstr, sizeof(ipstr));std::string clientip = ipstr;lg(Debug, "get a new client, ip: %s, port: %d, sockfd: %d", clientip.c_str(), clientport, sockfd);setnonblock(sockfd);addconnection(sockfd, event_in, nullptr, nullptr, nullptr);}else{if (errno == EWOULDBLOCK){break;}else if (errno == EINTR){continue;}else{break;}}}}bool IsConnectionSafe(int fd){auto iter = connections_.find(fd);if (iter == connections_.end()){return false;}return true;}void dispatcher(int timeout){int n = ep_ptr_->Wait(r_events_, num, timeout);for (int i = 0; i < n; i++){uint32_t event = r_events_[i].events;int sockfd = r_events_[i].data.fd;// 统一把异常问题转化成读写问题if (event & EPOLLERR){event |= (EPOLLIN | EPOLLOUT);}if (event & EPOLLHUP){event |= (EPOLLIN | EPOLLOUT);}// 处理读写if (IsConnectionSafe(sockfd) && (event & event_in)){if (connections_[sockfd]->rcb_){connections_[sockfd]->rcb_(connections_[sockfd]);}}if (IsConnectionSafe(sockfd) && (event & event_out)){if (connections_[sockfd]->wcb_){connections_[sockfd]->wcb_(connections_[sockfd]);}}}}void printconnection(){std::cout << "connections fds: " << std::endl;for (auto &e : connections_){std::cout << e.second->Fd() << " ";}std::cout << std::endl;}void loop(){quit_ = false;while (!quit_){dispatcher(3000);printconnection();}quit_ = true;}private:std::shared_ptr<epoll> ep_ptr_;                                    // 创建epoll对象std::shared_ptr<Sock> listensock_ptr_;                             // 构建了监听套接字对象;std::unordered_map<int, std::shared_ptr<connection>> connections_; // 构建了文件描述符和连接对象的映射epoll_event r_events_[num];uint16_t port_;bool quit_;
};
void setnonblock(int fd)
{int fl = fcntl(fd, F_GETFL);if (fl < 0){exit(NON_BLOCK);}fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}

相关文章:

高级IO——React服务器简单实现

3.4Reactor服务器实现 1.connect封装 ​ 每一个连接都要有一个文件描述符和输入输出缓冲区&#xff0c;还有读、写、异常处理的回调方法&#xff1b; ​ 还包括指向服务器的回指指针&#xff1b; class connection; class tcpserver;using func_t std::function<void(s…...

Qt使用插件QPluginLoader 机制开发

简介&#xff1a; 插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)是一种遵循一定规范的应用程序接口编写出来的程序。 Qt 提供了2种APIs来创建插件&#xff1a; 一种高级API&#xff0c;用于为Qt本身编写插件&#xff1a;自定义数据库驱动程序&#xff0c;图像格…...

双子座 Gemini1.5和谷歌的本质

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

二百三十、MySQL——MySQL表的索引

1 目的 梳理一下目前MySQL维度表的索引情况&#xff0c;当然网上也有其他博客专门讲MySQL索引的&#xff0c;我这边只是梳理一下目前的索引状况而已 2单列索引 2.1 索引截图 2.2 建表语句 3 联合索引 3.1 索引截图 3.2 建表语句 4 参考的优秀博客 http://t.csdnimg.cn/ZF7…...

并发编程之ThreadLocal使用及原理

ThreadLocal主要是为了解决线程安全性问题的 非线程安全举例 public class ThreadLocalDemo {// 非线程安全的private static final SimpleDateFormat sdf new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public static Date parse(String strDate) throws ParseExc…...

软件测试 测试开发丨Pytest结合数据驱动-yaml,熬夜整理蚂蚁金服软件测试高级笔试题

编程语言 languages: PHPJavaPython book: Python入门: # 书籍名称 price: 55.5 author: Lily available: True repertory: 20 date: 2018-02-17 Java入门: price: 60 author: Lily available: False repertory: Null date: 2018-05-11 yaml 文件使用 查看 yaml 文件 pych…...

软考数据库---2.SQL语言

主要记忆&#xff1a;表、索引、视图操作语句&#xff1b;数据操作&#xff1b;通配符、转义符&#xff1b;授权&#xff1b;存储过程&#xff1b;触发器 这部分等等整理一下: “”" 1、 数据定义语言。 SQL DDL提供定义关系模式和视图、 删除关系和视图、 修改关系模式的…...

基于顺序表实现通讯录

上篇我们讲了顺序表是什么&#xff0c;和如何实现顺序表。这篇文章我们将基于顺序表来实现通讯录。 文章目录 前言一、基于顺序表是如何实现的二、通讯录的头文件和实现文件三、通讯录的实现3.1 定义通讯录结构3.2 初始化通讯录3.3 销毁通讯录3.4 通讯录添加数据3.5 查找联系人…...

咸鱼之王_手游_开服搭建架设_内购修复无bug运营版

视频演示 咸鱼之王_手游_开服 游戏管理后台界面 源码获取在文章末尾 源码获取在文章末尾 源码获取在文章末尾 或者直接下面 https://githubs.xyz/y28.html 1.安装宝塔 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh &…...

【JSON2WEB】14 基于Amis的CRUD开发30分钟速成

【JSON2WEB】系列目录 【JSON2WEB】01 WEB管理信息系统架构设计 【JSON2WEB】02 JSON2WEB初步UI设计 【JSON2WEB】03 go的模板包html/template的使用 【JSON2WEB】04 amis低代码前端框架介绍 【JSON2WEB】05 前端开发三件套 HTML CSS JavaScript 速成 【JSON2WEB】06 JSO…...

Java入门教程||Java 变量

Java 变量 Java教程 - Java变量 变量由标识符&#xff0c;类型和可选的初始化程序定义。变量还具有范围&#xff08;可见性/生存期&#xff09;。 Java变量类型 在Java中&#xff0c;必须先声明所有变量&#xff0c;然后才能使用它们。变量声明的基本形式如下所示&#xff1…...

基于Java的校园快递一站式服务系统 (源码+文档+包运行)

一.系统概述 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本校园快递一站式服务系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞…...

通讯录的实现(顺序表版本)

我们知道通讯录是基于顺序表的前提下&#xff0c;要写好通讯录我们就要深入了解好顺序表。我们先来看看什么是顺序表。&#xff08;注意今天代码量有点多&#xff0c;坚持一下&#xff09;。冲啊&#xff01;兄弟们&#xff01; 顺序表的简单理解 对于顺序表&#xff0c;我们首…...

利用Sentinel解决雪崩问题(一)流量控制

1、解决雪崩问题的常见方式有四种: 超时处理:设定超时时间&#xff0c;请求超过一定时间没有响应就返回错误信息&#xff0c;不会无休止等待;舱壁模式:限定每个业务能使用的线程数&#xff0c;避免耗尽整个tomcat的资源&#xff0c;因此也叫线程隔离;熔断降级:由断路器统计业务…...

二叉树总结

递归返回值 1、如果需要搜索整棵二叉树且不用处理递归返回值&#xff0c;递归函数就不要返回值。 2、如果需要搜索整棵二叉树且需要处理递归返回值&#xff0c;递归函数就需要返回值。 3、如果要搜索其中一条符合条件的路径&#xff0c;那么递归一定需要返回值&#xff0c;…...

接口优化技巧

一、背景 针对老项目&#xff0c;去年做了许多降本增效的事情&#xff0c;其中发现最多的就是接口耗时过长的问题&#xff0c;就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案 二、接口优化方案总结 1.批处理 批量思想&#xff1a;批量操作数据库&a…...

【工具】NPS 内网穿透搭建

背景 在日常开发中经常会涉及到使用公网某个端口进行开发调试的情况&#xff0c;但我们日常开发的机器IP是非公网IP&#xff0c;所以需要使用内网穿透的手段&#xff0c;使我们的服务在公网上能被访问到。 常用的内网穿透工具分两大类&#xff0c;一类是付费/免费服务&#xf…...

【数学】主成分分析(PCA)的详细深度推导过程

本文基于Deep Learning (2017, MIT)&#xff0c;推导过程补全了所涉及的知识及书中推导过程中跳跃和省略的部分。 blog 1 概述 现代数据集&#xff0c;如网络索引、高分辨率图像、气象学、实验测量等&#xff0c;通常包含高维特征&#xff0c;高纬度的数据可能不清晰、冗余&am…...

微信跳转页面时发生报错

报错如下图所示&#xff1a; 解决方法&#xff1a;&#xff08;从下面四种跳转方式中任选一种&#xff0c;哪种能实现效果就用哪个&#xff09; 带历史回退 wx.navigateTo() //不能跳转到tabbar页面 不带历史回退 wx.redirectTo() //跳转到另一个页面wx.switchTab() //只能…...

8:系统开发基础--8.1:软件工程概述、8.2:软件开发方法 、8.3:软件开发模型、8.4:系统分析

转上一节&#xff1a; http://t.csdnimg.cn/G7lfmhttp://t.csdnimg.cn/G7lfm 课程内容提要&#xff1a; 8&#xff1a;知识点考点详解 8.1&#xff1a;软件工程概述 1.软件的生存周期 2.软件过程改进—CMM Capability Maturity Model能力成熟度模型 3.软件过程改进—CMMI—…...

【简单讲解下Symfony框架】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…...

[Linux基础]ln硬链接和ln -s软链接的方法参数及区别

区别&#xff1a; 1、ln创建硬链接&#xff1b;ln -s 创建软链接 2、硬链接的两个文件指向同一个inode&#xff08;inode&#xff1a;存放着文件的目录、权限、block块编号等信息&#xff09;&#xff1b;软链接的目标文件指向源文件&#xff0c;目标文件内存储的是源文件的目…...

开源博客项目Blog .NET Core源码学习(15:App.Hosting项目结构分析-3)

本文学习并分析App.Hosting项目中前台页面的关于本站页面和点点滴滴页面。 关于本站页面 关于本站页面相对而言布局简单&#xff0c;与后台控制器类的交互也不算复杂。整个页面主要使用了layui中的面包屑导航、选项卡、模版、流加载等样式或模块。   面包屑导航。使用layui…...

【muzzik 分享】3D模型平面切割

# 前言 一年一度的征稿到了&#xff0c;倒腾点存货&#xff0c;3D平面切割通常用于一些解压游戏里&#xff0c;例如水果忍者&#xff0c;切菜这些&#xff0c;今天我就给大家讲讲怎么实现3D切割以及其原理&#xff0c;帮助大家更理解3D中的 Mesh(网格)&#xff0c;以及UV贴图和…...

SCI一区 | Matlab实现OOA-TCN-BiGRU-Attention鱼鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测

SCI一区 | Matlab实现OOA-TCN-BiGRU-Attention鱼鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现OOA-TCN-BiGRU-Attention鱼鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测预测效果基本介绍模型描述程序…...

nodejs安装常用命令

安装 Node.js 后&#xff0c;你可以在命令行中使用以下常用命令&#xff1a; node&#xff1a;启动 Node.js 的交互式解释器&#xff0c;可以直接在命令行中执行 JavaScript 代码。 npm install <package-name>&#xff1a;安装一个 Node.js 模块&#xff0c;<packag…...

使用 Prometheus 在 KubeSphere 上监控 KubeEdge 边缘节点(Jetson) CPU、GPU 状态

作者&#xff1a;朱亚光&#xff0c;之江实验室工程师&#xff0c;云原生/开源爱好者。 KubeSphere 边缘节点的可观测性 在边缘计算场景下&#xff0c;KubeSphere 基于 KubeEdge 实现应用与工作负载在云端与边缘节点的统一分发与管理&#xff0c;解决在海量边、端设备上完成应…...

OSI七层网络模型 —— 筑梦之路

在信息技术领域&#xff0c;OSI七层模型是一个经典的网络通信框架&#xff0c;它将网络通信分为七个层次&#xff0c;每一层都有其独特的功能和作用。为了帮助记忆这七个层次&#xff0c;有一个巧妙的方法&#xff1a;将每个层次的英文单词首字母组合起来&#xff0c;形成了一句…...

状态模式:管理对象状态转换的动态策略

在软件开发中&#xff0c;状态模式是一种行为型设计模式&#xff0c;它允许一个对象在其内部状态改变时改变它的行为。这种模式把与特定状态相关的行为局部化&#xff0c;并且将不同状态的行为分散到对应的状态类中&#xff0c;使得状态和行为可以独立变化。本文将详细介绍状态…...

【论文阅读】MCTformer: 弱监督语义分割的多类令牌转换器

【论文阅读】MCTformer: 弱监督语义分割的多类令牌转换器 文章目录 【论文阅读】MCTformer: 弱监督语义分割的多类令牌转换器一、介绍二、联系工作三、方法四、实验结果 Multi-class Token Transformer for Weakly Supervised Semantic Segmentation 本文提出了一种新的基于变换…...

购物网站开发文献综述/google推广 的效果

电脑快捷键 Ctrl A 全选 Ctrl C 复制 Ctrl P 打印 Ctrl Y 恢复 Win D 返回桌面 Win E 打开我的电脑 Win L 锁定桌面 F2 文件重命名 F5 刷新 Ctrl shift T 网页关了&#xff0c;一键重新打开...

岷县城乡建设局网站/外包

前言 大家好&#xff0c;我是Allen&#xff0c;很多朋友是看我的技术编程专栏关注我的&#xff0c;我也一直致力于传播技术知识&#xff0c;但是在外企的这几年我发现&#xff0c;不光是编程技术&#xff0c;英语也是局限程序员发展的非常大的障碍&#xff0c;有不少想…...

日语网站设计/十大软件免费下载网站排行榜

c语言没有String类型&#xff0c;更没有String.length()方法&#xff0c;那么要怎么求数组长度呢&#xff1f; 数组举例&#xff1a;int arr[]{2,3,1,4}, char str[]{“Hello”} 获得数组长度可以用这个方法&#xff1a; 比如int数组 sizeOf(arr)/sizeOf(int) 可以求出数组长…...

做淘客网站需要企业的域名/百度关键词规划师入口

如今&#xff0c;电子书轻便海量的良好移动式体验受到广大年轻读者的喜爱。但是很多人也发现&#xff0c;有些电子书网站很贵&#xff0c;某些书籍还搜不到。今天&#xff0c;就给大家推荐6个电子书网站&#xff0c;不仅免费&#xff0c;而且品类丰富&#xff0c;能帮你找到99%…...

wordpress 手机模版/线上推广宣传方式有哪些

Sublime Text 3与Sublime Text 2的不同 其实有不少人写过如何让Sublime Text 2支持GB2312和GBK编码&#xff0c;例如这篇。基本原理就是先装好Package Control&#xff0c;然后再通过这个安装ConvertToUTF8的Package。 但是文中的方法在Sublime Text 3时代行不通了&#xff0c;…...

快速做网站的软件/市场seo是什么意思

双向链表的插入与删除 双向链表的结点定义 #define ElemType int //双向链表的存储结构 typedef struct DuLNode {ElemType data;DuLNode *prior;DuLNode *next; }DuLNode, *DuLinkList;双向链表的结点插入 画图表示&#xff0c;并在上述双向链表中一个已知结点p之后插入一…...