高级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封装 每一个连接都要有一个文件描述符和输入输出缓冲区,还有读、写、异常处理的回调方法; 还包括指向服务器的回指指针; class connection; class tcpserver;using func_t std::function<void(s…...
Qt使用插件QPluginLoader 机制开发
简介: 插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)是一种遵循一定规范的应用程序接口编写出来的程序。 Qt 提供了2种APIs来创建插件: 一种高级API,用于为Qt本身编写插件:自定义数据库驱动程序,图像格…...
双子座 Gemini1.5和谷歌的本质
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
二百三十、MySQL——MySQL表的索引
1 目的 梳理一下目前MySQL维度表的索引情况,当然网上也有其他博客专门讲MySQL索引的,我这边只是梳理一下目前的索引状况而已 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语言
主要记忆:表、索引、视图操作语句;数据操作;通配符、转义符;授权;存储过程;触发器 这部分等等整理一下: “”" 1、 数据定义语言。 SQL DDL提供定义关系模式和视图、 删除关系和视图、 修改关系模式的…...
基于顺序表实现通讯录
上篇我们讲了顺序表是什么,和如何实现顺序表。这篇文章我们将基于顺序表来实现通讯录。 文章目录 前言一、基于顺序表是如何实现的二、通讯录的头文件和实现文件三、通讯录的实现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变量 变量由标识符,类型和可选的初始化程序定义。变量还具有范围(可见性/生存期)。 Java变量类型 在Java中,必须先声明所有变量,然后才能使用它们。变量声明的基本形式如下所示࿱…...
基于Java的校园快递一站式服务系统 (源码+文档+包运行)
一.系统概述 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本校园快递一站式服务系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞…...
通讯录的实现(顺序表版本)
我们知道通讯录是基于顺序表的前提下,要写好通讯录我们就要深入了解好顺序表。我们先来看看什么是顺序表。(注意今天代码量有点多,坚持一下)。冲啊!兄弟们! 顺序表的简单理解 对于顺序表,我们首…...
利用Sentinel解决雪崩问题(一)流量控制
1、解决雪崩问题的常见方式有四种: 超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待;舱壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离;熔断降级:由断路器统计业务…...
二叉树总结
递归返回值 1、如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。 2、如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 3、如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,…...
接口优化技巧
一、背景 针对老项目,去年做了许多降本增效的事情,其中发现最多的就是接口耗时过长的问题,就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案 二、接口优化方案总结 1.批处理 批量思想:批量操作数据库&a…...
【工具】NPS 内网穿透搭建
背景 在日常开发中经常会涉及到使用公网某个端口进行开发调试的情况,但我们日常开发的机器IP是非公网IP,所以需要使用内网穿透的手段,使我们的服务在公网上能被访问到。 常用的内网穿透工具分两大类,一类是付费/免费服务…...
【数学】主成分分析(PCA)的详细深度推导过程
本文基于Deep Learning (2017, MIT),推导过程补全了所涉及的知识及书中推导过程中跳跃和省略的部分。 blog 1 概述 现代数据集,如网络索引、高分辨率图像、气象学、实验测量等,通常包含高维特征,高纬度的数据可能不清晰、冗余&am…...
微信跳转页面时发生报错
报错如下图所示: 解决方法:(从下面四种跳转方式中任选一种,哪种能实现效果就用哪个) 带历史回退 wx.navigateTo() //不能跳转到tabbar页面 不带历史回退 wx.redirectTo() //跳转到另一个页面wx.switchTab() //只能…...
8:系统开发基础--8.1:软件工程概述、8.2:软件开发方法 、8.3:软件开发模型、8.4:系统分析
转上一节: http://t.csdnimg.cn/G7lfmhttp://t.csdnimg.cn/G7lfm 课程内容提要: 8:知识点考点详解 8.1:软件工程概述 1.软件的生存周期 2.软件过程改进—CMM Capability Maturity Model能力成熟度模型 3.软件过程改进—CMMI—…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
