从零开始实现一个C++高性能服务器框架----Socket模块
此项目是根据sylar框架实现,是从零开始重写sylar,也是对sylar丰富与完善
项目地址:https://gitee.com/lzhiqiang1999/server-framework
简介
项目介绍:实现了一个基于协程的服务器框架,支持多线程、多协程协同调度;支持以异步处理的方式提高服务器性能;封装了网络相关的模块,包括socket、http、servlet等,支持快速搭建HTTP服务器或WebSokcet服务器。
详细内容:日志模块,使用宏实现流式输出,支持同步日志与异步日志、自定义日志格式、日志级别、多日志分离等功能。线程模块,封装pthread相关方法,封装常用的锁包括(信号量,读写锁,自旋锁等)。IO协程调度模块,基于ucontext_t实现非对称协程模型,以线程池的方式实现多线程,多协程协同调度,同时依赖epoll实现了事件监听机制。定时器模块,使用最小堆管理定时器,配合IO协程调度模块可以完成基于协程的定时任务调度。hook模块,将同步的系统调用封装成异步操作(accept, recv, send等),配合IO协程调度能够极大的提升服务器性能。Http模块,封装了sokcet常用方法,支持http协议解析,客户端实现连接池发送请求,服务器端实现servlet模式处理客户端请求,支持单Reator多线程,多Reator多线程模式的服务器。
Socket模块
1. 主要功能
- 对Linux下socket相关方法的封装,包括bind、listen、connect、read/write系列等方法。
- 支持快速创建TCP、UDP对应的Socket。
2. 功能演示
- 模拟一个请求百度的客户端,并打印出响应
IPAddress::ptr addr = Address::LookupAnyIPAddress("www.baidu.com:80");
// 创建socket
Socket::ptr socket = Socket::CreateTCP(addr);
// 连接
socket->connect(addr);
//发送数据
const char buf[] = "GET / HTTP/1.1\r\n\r\n";
int rt = socket->send(buf, sizeof(buf));
if(rt <= 0) {LOG_INFO(g_logger) << "send fail";return;
}//接收数据
std::string buffers;
buffers.resize(4096);
rt = socket->recv(&buffers[0], 4096);
if(rt <= 0) {LOG_INFO(g_logger) << "recv fail";return;
}LOG_INFO(g_logger) << buffers;
3. 模块介绍
3.1 Socket
- 对socket相关方法的封装,包括以下内容
- 创建各种类型的套接字对象的方法(TCP套接字,UDP套接字,Unix域套接字)
- 设置套接字选项,比如超时参数
- bind/connect/listen方法,实现绑定地址、发起连接、发起监听功能
- accept方法,返回连入的套接字对象
- 发送、接收数据的方法
- 获取本地地址、远端地址的方法
- 获取套接字类型、地址类型、协议类型的方法
- 取消套接字读、写的方法
class Socket : public std::enable_shared_from_this<Socket>, Noncopyable{public:typedef std::shared_ptr<Socket> ptr;typedef std::weak_ptr<Socket> weak_ptr;// 创建TCP Socket(满足地址类型)static Socket::ptr CreateTCP(johnsonli::Address::ptr address);// 创建UDP Socket(满足地址类型)static Socket::ptr CreateUDP(johnsonli::Address::ptr address);// 创建IPv4的TCP Socketstatic Socket::ptr CreateTCPSocket();// 创建IPv4的UDP Socketstatic Socket::ptr CreateUDPSocket();// 创建IPv6的TCP Socketstatic Socket::ptr CreateTCPSocket6();// 创建IPv6的UDP Socketstatic Socket::ptr CreateUDPSocket6();Socket(int family, int type, int protocol = 0);virtual ~Socket();int64_t getSendTimeout(); // 获取发送超时时间(毫秒)void setSendTimeout(int64_t v); // 设置发送超时时间(毫秒)int64_t getRecvTimeout(); // 获取接受超时时间(毫秒)void setRecvTimeout(int64_t v); // 设置接受超时时间(毫秒)// 获取sockopt @see getsockoptbool getOption(int level, int option, void* result, socklen_t* len);// 获取sockopt模板 @see getsockopttemplate<class T>bool getOption(int level, int option, T& result) {socklen_t length = sizeof(T);return getOption(level, option, &result, &length);}// 设置sockopt @see setsockoptbool setOption(int level, int option, const void* result, socklen_t len);// 设置sockopt模板 @see setsockopttemplate<class T>bool setOption(int level, int option, const T& value) {return setOption(level, option, &value, sizeof(T));}/*** @brief 接收connect链接* @return 成功返回新连接的socket,失败返回nullptr* @pre Socket必须 bind , listen 成功*/virtual Socket::ptr accept();/*** @brief 绑定地址* @param[in] addr 地址* @return 是否绑定成功*/virtual bool bind(const Address::ptr addr);/*** @brief 连接地址* @param[in] addr 目标地址* @param[in] timeout_ms 超时时间(毫秒)*/virtual bool connect(const Address::ptr addr, uint64_t timeout_ms = -1);virtual bool reconnect(uint64_t timeout_ms = -1);/*** @brief 监听socket* @param[in] backlog 未完成连接队列的最大长度* @result 返回监听是否成功* @pre 必须先 bind 成功*/virtual bool listen(int backlog = SOMAXCONN);/*** @brief 关闭socket*/virtual bool close();/*** @brief 发送数据* @param[in] buffer 待发送数据的内存* @param[in] length 待发送数据的长度* @param[in] flags 标志字* @return* @retval >0 发送成功对应大小的数据* @retval =0 socket被关闭* @retval <0 socket出错*/virtual int send(const void* buffer, size_t length, int flags = 0);/*** @brief 发送数据* @param[in] buffers 待发送数据的内存(iovec数组)* @param[in] length 待发送数据的长度(iovec长度)* @param[in] flags 标志字* @return* @retval >0 发送成功对应大小的数据* @retval =0 socket被关闭* @retval <0 socket出错*/virtual int send(const iovec* buffers, size_t length, int flags = 0);/*** @brief 发送数据* @param[in] buffer 待发送数据的内存* @param[in] length 待发送数据的长度* @param[in] to 发送的目标地址* @param[in] flags 标志字* @return* @retval >0 发送成功对应大小的数据* @retval =0 socket被关闭* @retval <0 socket出错*/virtual int sendTo(const void* buffer, size_t length, const Address::ptr to, int flags = 0);/*** @brief 发送数据* @param[in] buffers 待发送数据的内存(iovec数组)* @param[in] length 待发送数据的长度(iovec长度)* @param[in] to 发送的目标地址* @param[in] flags 标志字* @return* @retval >0 发送成功对应大小的数据* @retval =0 socket被关闭* @retval <0 socket出错*/virtual int sendTo(const iovec* buffers, size_t length, const Address::ptr to, int flags = 0);/*** @brief 接受数据* @param[out] buffer 接收数据的内存* @param[in] length 接收数据的内存大小* @param[in] flags 标志字* @return* @retval >0 接收到对应大小的数据* @retval =0 socket被关闭* @retval <0 socket出错*/virtual int recv(void* buffer, size_t length, int flags = 0);/*** @brief 接受数据* @param[out] buffers 接收数据的内存(iovec数组)* @param[in] length 接收数据的内存大小(iovec数组长度)* @param[in] flags 标志字* @return* @retval >0 接收到对应大小的数据* @retval =0 socket被关闭* @retval <0 socket出错*/virtual int recv(iovec* buffers, size_t length, int flags = 0);/*** @brief 接受数据* @param[out] buffer 接收数据的内存* @param[in] length 接收数据的内存大小* @param[out] from 发送端地址* @param[in] flags 标志字* @return* @retval >0 接收到对应大小的数据* @retval =0 socket被关闭* @retval <0 socket出错*/virtual int recvFrom(void* buffer, size_t length, Address::ptr from, int flags = 0);/*** @brief 接受数据* @param[out] buffers 接收数据的内存(iovec数组)* @param[in] length 接收数据的内存大小(iovec数组长度)* @param[out] from 发送端地址* @param[in] flags 标志字* @return* @retval >0 接收到对应大小的数据* @retval =0 socket被关闭* @retval <0 socket出错*/virtual int recvFrom(iovec* buffers, size_t length, Address::ptr from, int flags = 0);// 输出信息到流中virtual std::ostream& dump(std::ostream& os) const;virtual std::string toString() const;bool cancelRead(); // 取消读bool cancelWrite(); // 取消写 bool cancelAccept(); // 取消acceptbool cancelAll(); // 取消所有事件protected:void initSock(); // 设置socket属性void newSock(); // 创建socket m_sockfd = socket()virtual bool init(int sock); // 初始化sock,调用initSockprotected: int m_sockfd; /// socket句柄 int m_family; /// 协议簇 int m_type; /// 类型 int m_protocol; /// 协议 bool m_isConnected; /// 是否连接 Address::ptr m_localAddress; /// 本地地址 Address::ptr m_remoteAddress; /// 远端地址};// 流式输出socketstd::ostream& operator<<(std::ostream& os, const Socket& sock);
}
相关文章:
从零开始实现一个C++高性能服务器框架----Socket模块
此项目是根据sylar框架实现,是从零开始重写sylar,也是对sylar丰富与完善 项目地址:https://gitee.com/lzhiqiang1999/server-framework 简介 项目介绍:实现了一个基于协程的服务器框架,支持多线程、多协程协同调度&am…...
ld: library not found for -lcrt0.o
ld: library not found for -lcrt0.o 背景: Mac 系统编译的时候报错 语言:golang 原因: 代码使用了静态编译,-static。stack overflow 上说 This option will not work on Mac OS X unless all libraries (including libgcc.a…...
接口测试和功能测试的区别有哪些?说一些你不知道的知识
目录 接口测试和功能测试的区别 目的 测试范围 测试方法 重要性 编辑 举个例子 对于接口测试 对于功能测试 编辑 总结 接口测试和功能测试是软件测试中的两种常见测试类型,主要用于评估软件系统的质量。尽管这两种测试都是为了评估软件系统的性…...
深度学习实战——不同方式的模型部署(CNN、Yolo)
忆如完整项目/代码详见github:https://github.com/yiru1225(转载标明出处 勿白嫖 star for projects thanks) 目录 系列文章目录 一、实验综述 1.实验工具及及内容 2.实验数据 3.实验目标 4.实验步骤 二、ML/DL任务综述与模型部署知识…...
【论文阅读】GNN阅读笔记
A gentle introduction on gnn 前言 发表在distill的文章 图神经网络在应用上才刚刚开始 搭建了一个GNN playground 什么是图 图是表示实体之间的关系 可以分别表示成点向量、边向量、图向量 图可以分为有向图和无向图 数据是怎么表示成图 图片表示成图: …...
QT常用控件——QTreeWidget(树控件),QTableWidget控件
目录 ★先开个小灶,在此插句话:【有关Halcon与Qt联编变量转换】 QTreeWidget树控件 QTableWidget控件...
为什么学校购买小型数控机床而不是大型工业数控机床?
CNC 机器是计算机控制的设备,可以高精度和准确度地切割、雕刻、钻孔或雕刻各种材料。 它们广泛应用于制造、工程、设计和艺术行业。 CNC 机器具有不同的尺寸和功能,从小型台式机到大型工业机型。 人们可能想知道为什么学校会选择购买小型 CNC 机器而不是…...
【Go自学】一文搞懂Go append方法
我们先看一下append的源码 // The append built-in function appends elements to the end of a slice. If // it has sufficient capacity, the destination is resliced to accommodate the // new elements. If it does not, a new underlying array will be allocated. //…...
【压测】通过Jemeter进行压力测试(超详细)
文章目录背景一、前言二、关于JMeter三、准备工作四、创建测试4.1、创建线程组4.2、配置元件4.3、构造HTTP请求4.4、添加HTTP请求头4.5、添加断言4.6、添加察看结果树4.7、添加Summary Report4.8、测试计划创建完成五、执行测试计划总结背景 通过SpringCloudGateway整合Nacos进…...
C# | 上位机开发新手指南(七)加密算法
上位机开发新手指南(七)加密算法 文章目录上位机开发新手指南(七)加密算法前言加密算法的分类对称加密算法和非对称加密算法流加密算法和块加密算法分组密码和序列密码哈希函数和消息认证码对称加密与非对称对称加密优点缺点对称加…...
实验一 跨VLAN访问
目录 一、按照拓扑图配置VLAN,并实现跨VLAN间的访问。 二、实验环境 三、实验步骤 一、按照拓扑图配置VLAN,并实现跨VLAN间的访问。 1、配置好交换机的VLAN和各个终端的地址,实现各个VLAN内能连通。 2、开启两个交换机的VTY连接࿰…...
通信算法之130:软件无线电-接收机架构
1. 超外差式接收机 2.零中频接收机 3.数字中频接收机...
C++编程大师之路:从入门到精通-C++基础入门
文章目录前言主要内容C基础入门初识C第一个C程序注释变量常量关键字标识符命名规则数据类型整型sizeof关键字实型(浮点型)字符型转义字符字符串型布尔类型 bool数据的输入运算符算术运算符赋值运算符比较运算符逻辑运算符程序流程结构选择结构if语句三目…...
如何在千万级数据中查询 10W 的数据并排序
前言 在开发中遇到一个业务诉求,需要在千万量级的底池数据中筛选出不超过 10W 的数据,并根据配置的权重规则进行排序、打散(如同一个类目下的商品数据不能连续出现 3 次)。 下面对该业务诉求的实现,设计思路和方案优…...
RocketMQ消息文件过期原理
文章目录 消费完后的消息去哪里了?什么时候清理物理消息文件?这样设计带来的好处跳过历史消息的处理所有的消费均是客户端发起Pull请求的,告诉消息的offset位置,broker去查询并返回。但是有一点需要非常明确的是,消息消费后,消息其实并没有物理地被清除,这是一个非常特殊…...
Docker容器理解
目录 目录 一:简单理解操作系统 操作系统: 内核: 内核空间和用户空间: 二:简单理解文件系统 1:什么是文件系统 2:什么是root文件系统 三:docker 1:docker镜像 2&…...
SpringBoot 整合knife4j
文章目录SpringBoot 整合knife4j引入knife4j注解案例knife4j增强功能接口添加作者资源屏蔽访问页面加权控制接口排序分组排序请求参数缓存过滤请求参数禁用调试禁用搜索框SpringBoot 整合knife4j Knife4j是一款基于Swagger 2的在线API文档框架 在Spring Boot中,使…...
73-归并排序练习-LeetCode148排序链表
题目 给你链表的头结点 head ,请将其按升序排列并返回排序后的链表 。 示例 1: 输入:head [4,2,1,3] 输出:[1,2,3,4] 示例 2: 输入:head [-1,5,3,4,0] 输出:[-1,0,3,4,5] 示例 3ÿ…...
Hystrix学习笔记
Hystrix 官方文档: https://github.com/Netflix/Hystrix/wiki 是什么 In a distributed environment, inevitably some of the many service dependencies will fail. Hystrix is a library that helps you control the interactions between these distributed …...
面向对象编程(基础)8:关键字:package、import
目录 8.1 package(包) 8.1.1 语法格式 说明: 8.1.2 包的作用 8.1.3 应用举例 举例2:MVC设计模式 8.1.4 JDK中主要的包介绍 8.2 import(导入) 8.2.1 语法格式 8.2.2 应用举例 8.2.3 注意事项 8.1 package(包) package,称为包&#x…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
Win系统权限提升篇UAC绕过DLL劫持未引号路径可控服务全检项目
应用场景: 1、常规某个机器被钓鱼后门攻击后,我们需要做更高权限操作或权限维持等。 2、内网域中某个机器被钓鱼后门攻击后,我们需要对后续内网域做安全测试。 #Win10&11-BypassUAC自动提权-MSF&UACME 为了远程执行目标的exe或者b…...
OPENCV图形计算面积、弧长API讲解(1)
一.OPENCV图形面积、弧长计算的API介绍 之前我们已经把图形轮廓的检测、画框等功能讲解了一遍。那今天我们主要结合轮廓检测的API去计算图形的面积,这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能,常用的API…...
云原生时代的系统设计:架构转型的战略支点
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、云原生的崛起:技术趋势与现实需求的交汇 随着企业业务的互联网化、全球化、智能化持续加深,传统的 I…...
