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

网页广告怎么做免费网站seo排名优化

网页广告怎么做,免费网站seo排名优化,给医院做网站赚钱吗,百度关键词推广方案#x1f4da; 博主的专栏 #x1f427; Linux | #x1f5a5;️ C | #x1f4ca; 数据结构 | #x1f4a1;C 算法 | #x1f152; C 语言 | #x1f310; 计算机网络 |#x1f5c3;️ mysql 本文介绍了一种基于muduo库实现的主从Reactor模型高并发服务器框架…    博主的专栏  Linux   |   ️ C   |    数据结构  | C 算法 |  C 语言  |  计算机网络 |️ mysql 本文介绍了一种基于muduo库实现的主从Reactor模型高并发服务器框架以及前置知识准备。框架采用OneThreadOneLoop设计思想主Reactor负责监听连接子Reactor处理通信实现高效并发。前置知识包括1. 使用timerfd_create和timerfd_settime实现秒级定时任务2. 设计时间轮定时器管理连接超时3. 应用正则表达式解析HTTP请求4. 实现通用any类型容器存储不同协议上下文。测试表明该框架可有效支持高并发场景并提供了灵活的业务逻辑扩展接口。 目录 一、项目初了解 1.1 目标定位One Thread One Loop主从Reactor模型高并发服务器 1.2 模块关系图 二、前置知识技术点功能用例 2.1 C11中的bind这篇文章有详细的讲解 2.2 高效实现秒级定时任务 2.2.1 Linux系统提供了以下定时器解决方案 示例 2.2.2 时间轮定时器的基本思想理解以及设计完善 时间轮 shared_ptr来管理定时器任务对象 2.2.3 时间轮定时器的代码设计 ***智能指针的使用*** 2.2.4 时间轮定时器的代码实现 2.2.5 时间轮定时器的代码测试 2.3 正则库的简单使用 2.3.1 正则表达式基本认识 正则表达式匹配函数 2.3.2 正则表达式提取 HTTP 请求方法 2.3.3 正则表达式提取 HTTP 请求路径 2.3.4 正则表达式提取 HTTP 查询字符串 2.3.5 正则表达式提取 HTTP 协议版本 2.3.6 正则表达式提取 HTTP 元素细节完善 情况1所给字符串后边跟了\r\n用以上的e无法提取出字符串 情况2所给字符串根本没有查询字符串?userpupupasswd12312 2.4 实现通用的any类型 2.4.1通用类型容器any类设计思想 2.4.2通用类型容器any类结构设计 2.4.3通用类型容器any类功能实现 2.4.4 通用类型容器any类功能测试 2.4.5 通用类型容器C17中any的使用 一、项目初了解 基于muduo库的One Thread One Loop主从Reactor模型高并发服务器实现 我们实现的高并发服务器组件能够快速搭建高性能服务器架构。该组件提供多种应用层协议支持可便捷构建高性能应用服务器项目演示中已内置HTTP协议组件支持。 需要说明的是本项目定位为高并发服务器组件框架因此不包含具体业务逻辑实现。 1.1 目标定位One Thread One Loop主从Reactor模型高并发服务器 我们将采用主从Reactor模型构建服务器其中主Reactor线程专门负责监听连接请求确保高效处理新连接从而提升服务器并发性能。 当主Reactor获得新连接后会将其分配给子Reactor进行通信。各子Reactor线程独立监控其负责的描述符处理读写事件并完成数据传输及业务逻辑处理。 One Thread One Loop的核心思想是将所有操作集中在一个线程内完成每个线程对应一个独立的事件处理循环。 当前实现考虑到组件使用者的多样化需求默认仅提供主从Reactor模型而不内置业务层工作线程池。Worker线程池的实现与否完全由组件使用者根据实际需求自行决定。 1.2 模块关系图 ​ 二、前置知识技术点功能用例 2.1 C11中的bind这篇文章有详细的讲解 bind (Fn fn, Args... args); 见见使用 #include iostream #include string #include functionalvoid print(const std::string str, int num) {std::cout str num std::endl; }int main() {auto func std::bind(print, hello, std::placeholders::_1);func(10);return 0; } 利用bind的特性在设计线程池或任务池时可以将任务设置为函数类型。通过bind直接绑定任务函数的参数任务池只需取出并执行这些预绑定好的函数即可。 这种设计的优势在于任务池不需要关心具体任务的处理方式、函数设计或参数数量有效降低了代码之间的耦合度。 #include iostream #include string #include functional #include vector void print(const std::string str, int num) {std::cout str num std::endl; }int main() {using Task std::functionvoid();std::vectorTask array;array.push_back(std::bind(print, hello, 10));array.push_back(std::bind(print, linux, 20));array.push_back(std::bind(print, c, 30));array.push_back(std::bind(print, pupu, 40));for (auto f : array){f();}return 0; } 2.2 高效实现秒级定时任务 在高并发服务器环境中连接超时管理至关重要。长时间闲置的连接会持续占用系统资源因此需要及时关闭这些无效连接。 为此我们需要一个精准的定时任务机制定期清理超时连接。 2.2.1 Linux系统提供了以下定时器解决方案 timerfd_create-创建定时器 功能创建一个定时器 #include sys/timerfd.hint timerfd_create(int clockid, int flags);/** 参数说明* clockid: * - CLOCK_REALTIME 系统实时时间系统时间发生了改变就会出问题* - CLOCK_MONOTONIC 系统启动后的单调时间相对时间定时不会随着系统时间的改变而改变* * flags:* - 0 默认阻塞模式*/ 返回值文件描述符 Linux下“一切皆文件”定时器的操作也是跟文件操作并没有什么区别而定时器的原理就是 每隔一段时间定时器的超时时间系统就会给这个描述符对应的定时器写入一个8字节的数据 创建了一个定时器定时器定立的超时时间是3s也就是说每3s算一次超时 从启动开始每隔3s中系统就会给fd写入一个1表示从上一次读取数据到现在超时了1次 假设30s之后才读取数据则这时候就会读取到一个10表示上一次读取数据到限制超时了10次 timerfd_settime-启动定时器 功能启动定时器 int timerfd_settime(int fd, int flags, struct itimerspec *new, struct itimerspec *old); fd: timerfd_create返回的文件描述符 flags: 0-相对时间 1-绝对时间默认设置为0即可. new 用于设置定时器的新超时时间 old 用于接收当前定时器原有的超时时间   struct timespec {time_t tv_sec; /* Seconds */long tv_nsec;  /* Nanoseconds */ }; struct itimerspec {struct timespec it_interval; /* 第⼀次之后的超时间隔时间 */struct timespec it_value;    /* 第⼀次超时时间 */ }; 定时器每次超时时会自动向文件描述符(fd)写入8字节数据该数据表示从上次读取操作到当前读取操作之间发生的超时次数。 示例 #include stdio.h #include unistd.h #include fcntl.h #include sys/timerfd.h #include cstdintint main() {// 创建一个定时器int timerfd timerfd_create(CLOCK_MONOTONIC, 0);if (timerfd 0){perror(timerfd_create failed\n);return -1;}struct itimerspec itime;// 设置第一次超时时间为3s后itime.it_value.tv_sec 3;itime.it_value.tv_nsec 0;// 第一次超时后每次超时的间隔时间itime.it_interval.tv_sec 3;itime.it_interval.tv_nsec 0;timerfd_settime(timerfd, 0, itime, NULL);while (1){uint64_t times;int ret read(timerfd, times, 8);if (ret 0){perror(read error\n);return -1;}printf(超时了距离上一次超时了%ld次\n, times);}close(timerfd);return 0; } 这是一个定时器使用的示例每3秒会触发一次超时事件否则程序会阻塞在read数据读取操作上。基于此例我们可以实现每3秒检测一次超时连接并将超时的连接释放。 2.2.2 时间轮定时器的基本思想理解以及设计完善 时间轮 这个示例存在一个明显问题每次超时都需要遍历所有连接当连接数量达到上万时效率会非常低下。 为此我们可以改进方案根据每个连接最后一次通信的系统时间建立小根堆。这样只需检查堆顶的连接逐个释放超时的连接即可这将显著提升处理效率。 虽然上述方法能实现定时任务但这里要介绍另一种更优的解决方案时间轮 时间轮的灵感来自钟表机制。就像设定3点钟闹钟后时针走到3时就会触发铃声。 同样地我们可以定义一个数组和一个指针指针每秒移动一个位置。当指针移动到某个位置时就执行该位置对应的任务。 具体实现时如果想设定3秒后的任务只需将任务添加到指针当前位置3的位置。随着指针每秒移动一步3秒后就会到达对应位置执行该任务。 然而在同一个时间点可能会出现大量定时任务同时触发的情况。为此我们可以为数组的每个位置创建一个子数组下拉数组从而允许在相同时间点存储多个定时任务。 ​ tick滴答指针指向哪里就表示哪里的任务超时了3s后被执行 如果tick滴答是以秒作为计时单位则当前这数组有7个元素则最大定时时间就只有7s。 如果定时器想要设置一个超大时间的定时任务就可以使用多级时间轮 多级时间轮这里是一个天级60s 60min 24h ​ 缺陷 1.同一时刻的定时任务只能添加一个需要考虑如何在同一时刻支持添加多个定时任务 解决方案将时间轮的一维数组设计为二维数组时间轮一维数组的每一个节点也是一个数组 2.假设当前的定时任务是一个连接的非活跃销毁任务这个任务什么时候添加到时间轮中比较合适 一个连接30s内都没有通信则是一个非活跃连接这时候就销毁。但是一个连接在建立的时候添加了一个30s后销毁的任务并且这个连接30s内人家有数据通信在第30s的时候就不是一个非活跃连接。 思想需要在一个连接有IO事件产生的时候延迟定时任务的执行。 作为一个时间轮定时器本身并不关注任务类型只要是时间到了就需要被执行我们要研究的是如何绕开并且让该任务延迟 解决方案类的析构函数智能指针shared_ptr通过这两个技术可以实现定时任务的延时         1.使用一个类对定时任务进行封装类实例化每一个对象就是一个定时任务对象当对象被销毁的时候再去执行定时任务将定时任务的执行放到析构函数中         2.shared_ptr用于对new的对象进行空间管理当shared_ptr对一个对象进行管理的时候内部有一个计数器计数器为0的时候则释放所管理的对象。 int *a new int; std::shared_ptrint pi(a); ---a对象只有在pi计数为0的时候才会被释放 std::shared_ptrintpi1(pi);--针对pi又构建了一个shared_ptr对象则pi和pi1计数器为2 当pi和pi1中任意一个被释放的时候只有计数器-1因此他们管理的a对象并没有被释放只有当pi和pi1都被释放了计数器为0了这时候才会释放管理的a对象 基于这个思想我们可以使用shared_ptr来管理定时器任务对象智能指针的使用详解 shared_ptr来管理定时器任务对象 在实现过程中我们采用了智能指针shared_ptr。shared_ptr通过引用计数器管理对象生命周期只有当计数归零时才会释放资源。假设连接在第10秒进行一次通信我们会向定时任务队列中添加一个30秒后即第40秒执行的任务类对象的shared_ptr。此时两个任务shared_ptr的引用计数变为2。当第30秒的定时任务释放时计数减1变为1由于不为0不会触发实际析构。这意味着第30秒的任务自动失效而真正的资源释放会延迟到第40秒的任务执行时才完成 2.2.3 时间轮定时器的代码设计 #include memory #include functional #include iostream #include vector #include unordered_map #include cstdintusing TaskFunc std::functionvoid(); // 定时任务函数类型 using ReleaseFunc std::functionvoid(); class TimerTask { private:uint64_t _id; // 定时器任务对象IDuint32_t _timeout; // 定时任务的超时时间TaskFunc _task_cb; // 定时器对象要执行的定时任务ReleaseFunc _release; // 用于删除TimerWheel中保存的定时器对象信息 public:TimerTask(uint64_t id, uint32_t delay /*延迟时间*/, const TaskFunc cb) : _id(id), _timeout(delay), _task_cb(cb) {};~TimerTask(){_task_cb();_release();}void SetRelease(const ReleaseFunc cb) { _release cb; } };class TimerWheel { private:using WeakTask std::weak_ptrTimerTask;using PtrTask std::shared_ptrTimerTask;int _tick; // tick走到哪里就释放哪里的对象释放哪里就相当于执行哪里的任务int _capacity; // 表盘最大数量---其实就是最大延迟时间// 当我们要二次添加同一个定时器任务对象的时候得能够找到他们的同一个计数器使用weak_ptr辅助shared_ptr// 保存所有定时器的weak_ptr对象因为只有保存了WeakTask才有可能通过WeakTask构造出新的shared_ptr// 并且他们共享计数,并且WeakTask自身不影响计数std::vectorstd::vectorPtrTask _wheel;std::unordered_mapuint64_t, WeakTask _timers;public:TimerWheel() : _capacity(60), _tick(0), _wheel(_capacity) {}void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc cb); // 添加定时任务void TimerRefresh(uint64_t id); // 刷新/延迟定时任务 }; 这段代码实现了一个基于定时轮盘Timer Wheel的定时任务调度器用于管理和执行定时任务。以下是详细的代码讲解 1. TimerTask 类 功能 表示一个定时任务封装了任务的 ID、延迟时间、任务回调函数以及释放回调函数。 主要成员变量 _id 定时器任务对象的唯一标识符用于区分不同的定时任务。 _timeout 定时任务的超时时间即任务需要延迟执行的时间。 _task_cb 定时任务的具体执行逻辑当定时任务到期时会调用这个回调函数来执行相应的操作。 _release 用于删除 TimerWheel 中保存的定时器对象信息的回调函数在定时任务执行完毕或被取消时会调用这个函数来清理资源。 构造函数 初始化定时任务的 ID、延迟时间和任务回调函数。 析构函数 在定时任务对象被销毁时执行任务回调函数 _task_cb 和释放回调函数 _release 以确保任务被执行并且相关资源被正确释放。 SetRelease 方法 用于设置释放回调函数 _release 以便在需要时能够清理 TimerWheel 中的定时任务记录。 2. TimerWheel 类 功能 一个定时轮盘用于管理多个定时任务支持添加新的定时任务和刷新已存在的定时任务的延迟时间。 主要成员变量 _wheel 一个二维向量模拟定时轮盘的结构。每个元素是一个包含 PtrTask std::shared_ptrTimerTask 类型的向量代表定时轮盘上的一个槽slot。定时任务根据其延迟时间被放置在相应的槽中当轮盘的指针_tick移动到该槽时就会执行其中的定时任务。 _tick 表示定时轮盘当前所指向的槽的位置。随着时间的推移_tick 会不断递增当达到 _capacity 时会重新从 0 开始循环模拟轮盘的旋转。 _capacity 定时轮盘的最大容量即轮盘上槽的数量同时也是定时任务的最大延迟时间限制。在这个例子中初始容量被设置为 60意味着定时任务的延迟时间不能超过 60 个时间单位具体的时间单位可以根据实际应用场景来定义例如秒、毫秒等。 _timers 一个无序映射std::unordered_map用于保存所有定时任务的弱引用std::weak_ptrTimerTask。键是定时任务的 ID值是对应的弱引用。通过使用弱引用可以在不增加引用计数的情况下跟踪定时任务对象并且可以在需要时通过弱引用来构造新的共享指针从而访问定时任务对象。 ***智能指针的使用*** 使用 std::shared_ptrTimerTaskPtrTask来管理定时任务对象的生命周期确保多个部分可以安全地共享对定时任务对象的访问并且对象会在所有共享指针都释放后自动被销毁。 使用 std::weak_ptrTimerTaskWeakTask来保存定时任务的弱引用避免在 _timers 映射中直接保存共享指针而导致对象的引用计数增加从而防止定时任务对象被意外地延长生命周期。通过弱引用可以在需要时检查定时任务对象是否仍然存在并在存在时获取其共享指针。 任务生命周期管理 ​ 2.2.4 时间轮定时器的代码实现 #include memory #include functional #include iostream #include vector #include unordered_map #include cstdint#include unistd.husing TaskFunc std::functionvoid(); // 定时任务函数类型 using ReleaseFunc std::functionvoid(); class TimerTask { private:uint64_t _id; // 定时器任务对象IDuint32_t _timeout; // 定时任务的超时时间bool _canceled; // false表示未被取消true表示被取消TaskFunc _task_cb; // 定时器对象要执行的定时任务ReleaseFunc _release; // 用于删除TimerWheel中保存的定时器对象信息 public:TimerTask(uint64_t id, uint32_t delay /*延迟时间*/, const TaskFunc cb): _id(id), _timeout(delay), _task_cb(cb), _canceled(false) {}~TimerTask(){if (_canceled false)_task_cb();_release();}void Cancel(){_canceled true;}void SetRelease(const ReleaseFunc cb) { _release cb; }uint32_t DelayTime() { return _timeout; }; };class TimerWheel { private:using WeakTask std::weak_ptrTimerTask;using PtrTask std::shared_ptrTimerTask;int _tick; // tick走到哪里就释放哪里的对象释放哪里就相当于执行哪里的任务int _capacity; // 表盘最大数量---其实就是最大延迟时间// 当我们要二次添加同一个定时器任务对象的时候得能够找到他们的同一个计数器使用weak_ptr辅助shared_ptr// 保存所有定时器的weak_ptr对象因为只有保存了WeakTask才有可能通过WeakTask构造出新的shared_ptr// 并且他们共享计数,并且WeakTask自身不影响计数std::vectorstd::vectorPtrTask _wheel;std::unordered_mapuint64_t, WeakTask _timers;private:void RemoveTimerInfo(uint64_t id){auto it _timers.find(id);if (it ! _timers.end()){_timers.erase(it);}}public:TimerWheel() : _capacity(60), _tick(0), _wheel(_capacity) {}// 添加定时任务void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc cb){PtrTask pt(new TimerTask(id, delay, cb));pt-SetRelease(std::bind(TimerWheel::RemoveTimerInfo, this, id));int pos (_tick delay) % _capacity;_wheel[pos].push_back(pt);_timers[id] WeakTask(pt);}// 刷新/延迟定时任务void TimerRefresh(uint64_t id){// 通过保存的定时器对象的weak_ptr构造一个shared_ptr出来添加到轮子中auto it _timers.find(id);if (it _timers.end()){// 没找到定时任务没法刷新没法延时return;}PtrTask pt it-second.lock(); // lock获取weak_ptr所管理对象对应的的shared_ptrint delay pt-DelayTime();int pos (_tick delay) % _capacity;_wheel[pos].push_back(pt);}// 取消一个定时任务void TimerCancel(uint64_t id){// 通过保存的定时器对象的weak_ptr构造一个shared_ptr出来添加到轮子中auto it _timers.find(id);if (it _timers.end()){// 没找到定时任务没法刷新没法延时return;}PtrTask pt it-second.lock(); // lock获取weak_ptr所管理对象对应的的shared_ptrif (pt)pt-Cancel();}// 这个函数每秒钟执行一次相当于秒针向后走了一步void RunTimerTask(){_tick (_tick 1) % _capacity;_wheel[_tick].clear(); // 清空指定位置的数组就能将数组中保存的所有管理对象的shared_ptr释放掉} }; 1. 动态创建定时任务对象 在 TimerAdd 函数中使用 std::shared_ptr 动态创建 TimerTask 对象 PtrTask pt(new TimerTask(id, delay, cb)); 这种方式允许在代码运行时根据需要创建定时任务对象并通过智能指针管理其生命周期。 2. 设置释放回调函数 在创建定时任务对象后调用 SetRelease 方法将 RemoveTimerInfo 函数绑定到定时任务对象的释放回调函数上 pt-SetRelease(std::bind(RemoveTimerInfo, this, id)); 当定时任务对象被销毁时会自动调用 RemoveTimerInfo 函数从 _timers 映射中移除该定时任务的记录。 3. 计算定时任务在轮盘上的位置 在 TimerAdd 和 TimerRefresh 函数中根据当前的 _tick 值轮盘指针位置和任务的延迟时间 delay计算定时任务在轮盘上的位置 int pos (_tick delay) % _capacity; 这种方法确保定时任务能够根据其延迟时间被正确地放置在轮盘的相应槽中。 4. 将定时任务添加到轮盘 在 TimerAdd 和 TimerRefresh 函数中将定时任务的共享指针添加到 _wheel 的对应槽中 _wheel[pos].push_back(pt); 这使得定时任务能够在轮盘到达该槽时被触发。 5. 更新定时任务映射 在 TimerAdd 函数中将定时任务的弱引用添加到 _timers 映射中 _timers[id] WeakTask(pt); 通过弱引用可以在不增加引用计数的情况下跟踪定时任务对象便于后续的刷新操作。 6. 刷新定时任务 在 TimerRefresh 函数中使用弱引用来获取定时任务的共享指针并重新计算其在轮盘上的位置 PtrTask pt it-second.lock(); ... int pos (_tick delay) % _capacity; _wheel[pos].push_back(pt); 这允许在定时任务已经存在的情况下更新其延迟时间并重新将其添加到轮盘中。 7. 执行定时任务 在 RunTimerTask 函数中将轮盘指针向前移动并清空当前槽中的所有定时任务 _tick (_tick 1) % _capacity; _wheel[_tick].clear(); 清空槽中的任务会减少这些任务的引用计数如果引用计数变为零任务对象将被销毁从而触发其析构函数执行任务逻辑和释放操作。 8. 在 TimerTask 类中新增任务取消功能 新增 _canceled 成员变量 布尔类型默认值为 false表示定时任务未被取消。当 _canceled 为 true 时表示任务已被取消。 新增 Cancel 方法 用于将 _canceled 标志设置为 true表示取消该定时任务。 在析构函数中增加条件判断 如果任务未被取消_canceled false则执行任务回调函数 _task_cb 。否则跳过任务的执行直接调用释放回调函数 _release 。这实现了任务取消功能即当任务被取消时其对应的回调函数不会被执行。 9. 在 TimerWheel 类中新增 TimerCancel 方法 调用定时任务的 Cancel 方法 如果成功获取到共享指针即定时任务对象存在则调用该定时任务对象的 Cancel 方法将其 _canceled 标志设置为 true从而取消任务。 2.2.5 时间轮定时器的代码测试 通过以下测试代码测试代码的正确性 // 测试类 // 通过释放过程来看任务执行情况 class Test { private: public:Test() { std::cout 构造 std::endl; }~Test() { std::cout 析构 std::endl; } };void DelTest(Test *t) {delete t; }int main() {TimerWheel tw;Test *t new Test();tw.TimerAdd(8, 5, std::bind(DelTest, t));for (int i 0; i 5; i){sleep(1);tw.TimerRefresh(8); // 刷新定时任务tw.RunTimerTask(); // 向后移动秒针std::cout 刷新了一下定时任务重新需要5s才会被销毁 std::endl;}tw.TimerCancel(8);while (1){std::cout ----------------------- std::endl;sleep(1);tw.RunTimerTask(); // 向后移动指针}return 0; } 2.3 正则库的简单使用 2.3.1 正则表达式基本认识 正则表达式就是一种字符串匹配规则。正则库就是给我们提供一套接口让我们使用正则匹配功能。正则表达式能够简化HTTP请求的解析过程主要减轻程序员的工作负担让开发的HTTP组件库更易使用。需要注意的是这种方式虽然提高了开发效率但在处理速度上会略逊于直接的字符串操作。 regex - C Reference 正则表达式匹配函数 std::regex_match 功能精确匹配整个字符串 参数 bool regex_match(const std::string str, // 待匹配字符串std::smatch matches, // 存储匹配结果const std::regex pattern, // 正则表达式std::regex_constants::match_flag_type flags std::regex_constants::match_default ); HTTP 使用场景匹配完整请求行如 GET /index.html HTTP/1.1 std::regex_search 功能在字符串中搜索子匹配 参数同 regex_match HTTP 使用场景提取请求头中的键值对如 Host: www.example.com 示例 #include iostream #include string #include regexint main() {std::string str /numbers/1234;// 以numbers作为起始字符串数字是\d(多加一个\转义)// 匹配以/numbers/起始后边跟了一个或多个数字字符的字符串并且在匹配的过程中提取这个匹配到的数字字符串std::regex e(/numbers/(\\d));std::smatch matches;bool ret std::regex_match(str, matches, e);if (ret false){return -1;}for (auto s : matches){std::cout s std::endl;}return 0; } 输出 /numbers/1234 1234 2.3.2 正则表达式提取 HTTP 请求方法 HTTP请求行格式 GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1\r\n  示例​​​​​请求方法的匹配 GET|HEAD|POST|PUT|DELETE表示匹配并提取其中任意一个字符串 #include iostream #include string #include regexint main() {std::string str GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1;std::smatch matches;// 请求方法的匹配:GET HEAD POST PUT DELETEstd::regex e((GET|HEAD|POST|PUT|DELETE) .*);bool ret std::regex_match(str, matches, e);if (ret false){std::cout 未找到\n;return -1;}for (auto s : matches){std::cout s std::endl;}return 0; } 输出 GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1 GET 2.3.3 正则表达式提取 HTTP 请求路径 示例[^?]* [^?]表示匹配一个非?字符后边*代表匹配0次或多次表示匹配1次或多次 std::regex e((GET|HEAD|POST|PUT|DELETE) ([^?]*) .*); 输出 GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1 GET /pupus_blog/login 2.3.4 正则表达式提取 HTTP 查询字符串 示例\\?(.*)          \\?表示原始的字符后边的(.*)表示提取?之后的任意字符0次或多次直到遇到空格 std::regex e((GET|HEAD|POST|PUT|DELETE) ([^?]*)\\?(.*) .*); 输出 GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1 GET /pupus_blog/login userpupupasswd12312 2.3.5 正则表达式提取 HTTP 协议版本 示例(HTTP/1\\.[01]) [01]表示匹配的是里边的01任意一个字符 std::regex e((GET|HEAD|POST|PUT|DELETE) ([^?]*)\\?(.*) (HTTP/1\\.[01]).*); 输出 GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1 GET /pupus_blog/login userpupupasswd12312 HTTP/1.1 2.3.6 正则表达式提取 HTTP 元素细节完善 情况1所给字符串后边跟了\r\n用以上的e无法提取出字符串 std::string str GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1\r\n; 如果\n|\r\n 输出结果 ​ 得到这样的结果并不是我们的目的我们的目的是过滤掉\r\n 使用?:\n|\r\n 输出结果分析的串后边跟的是\n或者\r\n GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1GET /pupus_blog/login userpupupasswd12312 HTTP/1.1 但如果分析的串后边没有\r\n或者\n就输出失败 解决办法?:\n|\r\n)? (?:\n|\r\n)? : (?: ...) 表示匹配某个格式字符串但是不提取他最后的?表示的是匹配前边的表达式0次或1次 std::regex e((GET|HEAD|POST|PUT|DELETE) ([^?]*)\\?(.*) (HTTP/1\\.[01])(?:\n|\r\n)?);输出结果 GET /pupus_blog/login?userpupupasswd12312 HTTP/1.1 GET /pupus_blog/login userpupupasswd12312 HTTP/1.1 情况2所给字符串根本没有查询字符串?userpupupasswd12312 由现有的e无法输出 解决办法(?:\\?(.*))? 匹配一个可选的问号?如果问号存在则捕获问号后的所有内容包括空内容作为一个分组。 std::regex e((GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?); 输出 GET /pupus_blog/login HTTP/1.1 GET /pupus_blog/loginHTTP/1.1 2.4 实现通用的any类型 每个Connection都需要管理网络连接这最终都会涉及应用层协议的处理。因此Connection中需要配置一个协议处理上下文来控制处理流程。考虑到应用层协议种类繁多为避免耦合这个协议解析上下文不应偏向特定协议而应该能够容纳任意协议的上下文信息这就需要一个通用的数据类型来存储不同的数据结构。在C语言中通用类型可通过void*实现。而在C中boost库和C17都提供了any这一灵活的类型。如需提高代码可移植性并减少第三方库依赖可以选择使用C17的any特性或自行实现。 2.4.1通用类型容器any类设计思想 设计实现一个any类 是一个容器容器中可以保存各种不同类型的数据 解决方案 1.模版--不可用 template class T class Any { private:T _content; }; 实例化对象的时候必须指定容器保存的数据类型 Anyint a; 我们需要的是直接用Any aa 10a abcd.... 2.设计嵌套类类型擦除(Type Erasure)技术的核心思想允许在单个容器中存储任意类型的值 多态存储架构基类 holder 作为抽象接口模板子类placeholderT 存储具体类型值 在Any类中存储了holder类的指针。当需要保存数据时Any容器只需通过placeholder子类实例化一个特定类型的子类对象由该子类对象来实际存储数据。 ​ 2.4.2通用类型容器any类结构设计 核心设计思想 类型擦除通过基类指针指向模板派生类擦除具体类型信息 多态克隆通过虚函数实现深拷贝 类型安全访问运行时检查类型匹配 class Any { private:class holder{public:virtual ~holder() {}virtual std::type_info type() 0;virtual holder *clone() 0;};template class Tclass placeholder : holder{public:placeholder(const T val) _val(val) {}// 获取子类对象保存的数据类型std::type_info type() override;// 针对当前的对象自身克隆出一个新的子类对象holder *clone() override;};holder *_content; // 在new一个子类对象的时候指定类型让父类指向这个子类 public:Any();template class TAny(const T val);Any(const Any other);~Any();// 返回在子类对象中保存的数据的指针template class TT *get();// 赋值运算符的重载函数template class TAny operator(const T val);Any operator(const Any other); }; 2.4.3通用类型容器any类功能实现 #include iostream #include typeinfo #include cassert #include string class Any { private:class holder{public:virtual ~holder() {}virtual const std::type_info type() 0;// 深拷贝支持多态克隆确保复制完整对象virtual holder *clone() 0;};template class Tclass placeholder : public holder{public:placeholder(const T val) : _val(val) {}// 获取子类对象保存的数据类型const std::type_info type() override{return typeid(T);}// 针对当前的对象自身克隆出一个新的子类对象holder *clone() override{return new placeholder(_val);}public:T _val;};// 指向不同类型数据的通用接口holder *_content; // 在new一个子类对象的时候指定类型让父类指向这个子类public:// 无参构造Any() : _content(nullptr){}template class T// 通用构造Any(const T val) : _content(new placeholderT(val)){}// 拷贝构造Any(const Any other) : _content(other._content ? other._content-clone() : nullptr){}~Any(){delete _content;}//为了进行一个连续的交换Any swap(Any other){std::swap(_content, other._content);return *this;}// 返回在子类对象中保存的数据的指针template class TT *get(){if (!_content)return nullptr;// 想要获取的数据类型必须和保存的数据类型一致assert(typeid(T) _content-type());// 向下转型获取存储的值return static_castplaceholderT *(_content)-_val;}// 赋值运算符的重载函数template class TAny operator(const T val){// 为val构造一个临时的通用容器然后与当前容器自身进行指针交换临时对象释放的时候原先保存的数据也就被释放Any(val).swap(*this); // 创建临时对象并交换return *this;}Any operator(const Any other){Any(other).swap(*this); // 拷贝构造临时对象并交换return *this;} }; 类结构分析  ​ 注意模板派生类 placeholder派生类 关键点必须使用 public 继承基类 holder 2.4.4 通用类型容器any类功能测试 示例1 class Test { public:Test(){std::cout 构造 std::endl;}Test(const Test t){std::cout 拷贝构造 std::endl;}~Test(){std::cout 析构 std::endl;} };int main() {Any a;{Test t;a t;}a 10;int *pa a.getint();std::cout *pa std::endl;a std::string(nihao);std::string *ps a.getstd::string();std::cout *ps std::endl;return 0; } 运行结果 构造 拷贝构造 析构 析构 10 nihao  示例2 int main() {{Any a;Test t;a t;}while (1){sleep(1);}return 0; } 运行结果 ​ 未来可以选择使用boost库\c17\自己实现的Any  2.4.5 通用类型容器C17中any的使用 std::any - cppreference.cn - C参考手册 使用 ​ 结语        随着这篇博客接近尾声我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战但正是这些挑战让我们不断成长和进步。我在准备这篇文章时也深刻体会到了学习与分享的乐趣。              在此我要特别感谢每一位阅读到这里的你。是你的关注和支持给予了我持续写作和分享的动力。我深知无论我在某个领域有多少见解都离不开大家的鼓励与指正。因此如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处都欢迎你慷慨赐教。         你的每一条反馈都是我前进路上的宝贵财富。同时我也非常期待能够得到你的点赞、收藏关注这将是对我莫大的支持和鼓励。当然我更期待的是能够持续为你带来有价值的内容。
http://www.hkea.cn/news/14388021/

相关文章:

  • 临沂做网站的公司有哪些腰椎间盘突出压迫神经腿疼怎么治
  • 怎么制作营销网站如何用快站做pc端网站
  • 网站建设销售如何接单网页设计模板百度云
  • 个人备案网站做淘宝客可以用吗搭建平台 能说会写
  • 请问下网站开发怎么弄江苏设计网站电话
  • 找人做海报在什么网站找综合性门户网站有
  • 地方门户网站资讯该怎么做上海有实力的seo推广咨询
  • 网站开发外包公司合同在线做拓扑图的网站
  • 做网站和seo流程Wordpress做物联网
  • 建站教程wp企业网络营销企业网站建设章节习题
  • 手机建站平台微点手赚专门做鞋子的网站有哪些
  • 网站 做 app开发手机网站建设文章
  • 建站公司哪个平台最好养老网上服务平台
  • 哪个网站做兼职有保障北京市建设工程信息网站
  • 杭州网站建设开发外包公司专升本要什么条件
  • 免费网站建站2773店面门头设计网站
  • 淘宝联盟 网站备案网站开发用什么数据库
  • 上海某家具网站建设方案英文网站建设980
  • 网站信息核验单网站开发最适合的浏览器
  • 小程序代码做网站淮安设计网站
  • 网泰网站建设邯郸高端网站建设价格
  • 网站制作的主要技术网奇seo赚钱培训
  • 个人网站如何获得流量seo 优化是什么
  • 建立网站的公司旅游公共信息服务网站建设及服务质量标准
  • 网站建设技术服务wordpress卡密销售
  • 网站建设属于电子方案网站建设方案
  • 网站系统中备案申请表培训网站方案
  • 樱花12e56手机优化助手下载
  • 开电商网站需要多少钱重庆网站建设如何
  • 怎么做网站链接天猫运营培训