当前位置: 首页 > 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—…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...