- 博客(477)
- 收藏
- 关注
原创 【jsonRpc项目】客户端的Requestor模块,RpcCaller模块
std::promise:这也是一个模板类,它提供了一种存储值(或异常)的方式,这个值可以被同一个线程或其他线程中的std::future对象读取。既然,我们定义了这么一种请求描述结构体,我们的客户端肯定不止一个请求,那么每一个请求都需要创建一个请求描述结构体,这样子的话,客户端就会有很多请求描述结构体,那么我们就需要将其管理起来。事实上呢,在我们的Requestor模块里面,就定义了一个哈希表<请求ID,请求描述结构体>,这样子将我们的请求描述结构体管理起来了。这个ID作为请求的一部分被发送至服务器。
2026-01-26 13:47:30
433
原创 【jsonRpc项目】服务端的RpcRouter模块
首先,我们先回答一个问题还记得Dispatcher类是怎么进行设计的吗Dispatcher内部维护一个“消息类型-处理函数”映射表(通常实现为或类似哈希结构)。框架的使用者可以提前向Dispatcher模块注册不同消息类型对应的业务回调函数的注册。事实上,我们的RpcRouter模块就会写好消息类型是RPC请求的业务处理回调函数,然后在Dispatcher模块里面统一进行注册的。当一条消息抵达时,Dispatcher通过其类型标识快速查找映射表,获取对应的回调函数并执行,完成消息的处理闭环。
2026-01-26 09:28:44
418
原创 【jsonRpc项目】Dispatcher模块
你可以想象一下这个场景:你的服务器程序就像一个前台接待员,每天要处理各种各样的客户请求,比如有人来咨询、有人来办业务、有人来投诉。同样,它也要给客户端发出各种不同的通知。现在,最直接的编程方法就是:在这个“接待员”的函数里,写一大堆语句。收到一个消息:如果 消息类型是A,就 执行A的处理逻辑;否则如果 消息类型是B,就 执行B的处理逻辑;否则如果 消息类型是C,就 执行C的处理逻辑;...(可能有几十个)这种方法一开始看似简单直接,但很快就会变得难以管理。
2026-01-25 14:52:53
553
原创 【jsonRpc项目】基本的宏定义,抽象层和具象层的实现
我们这个我们不能直接使用id,这个键名来进行赋值,因为如果说这个键名后面改掉了,我们后面就需要满代码的去寻找这个id,进行替换,这个是非常危险的,我们必须使用一个宏来表示即可,后面我们只需要去修改这个宏即可实现整个项目的对应位置的替换。但是注意,我们之前定义的宏都是字符串,而这里赋值的是Json::Value类型,所以直接使用字符串宏是没问题的。这样,当字段名需要改变时,我们只需要修改宏定义,而不用在整个代码库中搜索替换。现在我们就开始编写我们的宏定义。
2026-01-24 16:50:27
599
原创 【jsonRpc】项目介绍
目录一.项目概览二.服务端模块划分2.1.Network模块2.2.Protocol模块(应用层通信协议模块)2.3.Dispatcher模块2.4.RpcRouter模块2.5.Publish-Subscribe(发布订阅)模块2.6.Registry-Discovery模块三.客户端模块划分3.1.Network:⽹络通信模块3.2. Protocol:应⽤层通信协议模块3.3.Dispatcher:消息分发处理模块3.4.Requestor模块3.5.RpcCaller 模块3.6.Publish-S
2026-01-23 09:41:29
643
原创 【JSONRpc项目】项目前置准备
当我们在一个进程里面需要调用另一个进程中实现的函数时,应当如何实现?这种场景下,RPC 技术提供了一种成熟的解决方案。RPC(远程过程调用)是一种计算机通信协议,允许当前程序调用位于另一个程序(通常是在网络中的远程机器上)的函数,而开发者无需显式编写处理网络通信的代码。它的核心目标是让远程调用在形式上尽可能接近本地调用,从而简化分布式系统的开发。也就是说,无论函数是在本地还是远程,对程序员而言,调用方式看起来基本一致。
2026-01-16 15:02:30
682
原创 【仿Muduo库项目】HTTP服务器搭建
每次HTTP请求都会建立一个新的TCP连接,请求完成后立即关闭连接,这意味着每一次HTTP请求都会创建一个Connection对象,这就刚好和我们上面的代码对上了。我们在这个测试过程中,客户端仅仅只发送了一次数据,然后就循环等待服务器的响应,前10秒(超时释放时间)内,这个连接就保持着,但是一过了超时时间,这个连接就自动释放了。在HTTP/1.0中,默认使用短连接,如果需要长连接,需要在请求头中加上"Connection: keep-alive"。这就说明我们的服务器能很好的处理这个数据粘包问题。
2026-01-15 20:40:37
629
原创 【仿Muduo库项目】HTTP模块4——HttpServer子模块
这个功能其实就是很简单,就是根据HTTP里面的资源请求路径,来读取服务器里面对应文件里面的内容,然后将内容放到我们的HTTP响应的正文里面,然后在HTTP响应报头里面设置一个字段Content-Type,就是正文的类型。但是,还是不太够,我们的静态文件请求就必须是请求的就必须是一个已经存在的文件,那对于目录我们怎么进行处理呢?现在准备工作就差不多了,最后,我们需要去判断这个文件是不是已经在我们的服务器上存在,如果存在,就判定为静态文件请求,否则,则判定不是静态文件请求。
2026-01-13 16:29:21
719
原创 【仿Muduo库项目】HTTP模块2——HttpRequest子模块,HttpResponse子模块
虽然 RFC 1945 和 RFC 2068 规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将 302 响应视为 303 响应,并且使用 GET 方式访问在 Location 中规定的 URI,而无视原先请求的方法。附带条件的请求是指采用 GET 方法的请求报文中包含 If-Match,If-Modified Since,If-None-Match,If-Range,If-Unmodified-Since 中任一首部。但是,对于处理响应时的行为,每种浏览器有可能出现不同的情况。
2026-01-11 15:57:46
575
原创 【仿Muduo库项目】HTTP模块1——Util子模块
从这篇博客开始,就是顶层协议处理模块了,只不过我们这里设置的协议其实是HTTP协议。HTTP 协议模块旨在为高并发服务器提供协议层面的支持,基于该模块可以更便捷地搭建符合特定协议的服务端。提供 HTTP 协议处理过程中所需的各类工具函数,例如 URL 编解码、文件读写等公共功能,为上层模块提供基础支持。负责封装 HTTP 请求数据。当请求被解析后,其方法、路径、头部、主体等信息将存储于该模块的对象中,供后续处理流程使用。用于构造 HTTP 响应数据。
2026-01-11 12:55:27
607
原创 【仿Muduo库项目】TcpServer模块,回显服务器搭建
它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能,最多可以模拟3万个并发连接去测试网站的负载能力。TcpServer模块是网络服务器架构中的核心管理单元,它通过对多个底层子模块进行整合与调度,提供了一个高层、易用的接口,使得搭建和管理一个高性能服务器变得简单明了。当然,这些回调函数都只是在TcpServer这里暂存,TcpServer应该将这些回调函数传递给每一个新的连接对应的Connection。我们后续写完整个项目的时候,会在最后进行详细的压测分析。
2026-01-10 20:16:12
1024
原创 【仿Muduo库项目】Accept模块,LoopThread模块,LoopThreadPool模块
在构造Acceptor对象时,会创建一个监听套接字,并将其绑定到指定的端口上,开始监听来自客户端的连接请求。Acceptor会将监听套接字注册到事件循环中,并启动读事件监控。读事件对应着新的连接请求到达。当监听套接字的读事件被触发(即有新的连接请求到达),Acceptor会调用操作系统提供的accept函数来获取新连接,得到一个新的连接套接字(文件描述符)。Acceptor模块并不关心如何管理这个新连接,它只是将新连接的文件描述符通过一个预先设置的回调函数传递给上层模块(通常是服务器模块)。
2026-01-10 10:30:11
606
原创 【Muduo库】套接字模块,Channel模块,Poller模块
这两个函数我们目前这个模块是实现不了的,仔细观察一下就会发现,这两个函数都依赖于一个EventLoop对象,也就是我们这里的成员变量EventLoop *_loop;” 然后,基于这个准确的信息,再执行精确的清理操作,比如“仅停止当前正在被监控的可读事件”。注意,在epoll中,读和写事件都会监控到挂起事件,触发后可能还需要读取缓冲区中剩余的数据。这些事件标志在设计时就被定义为位标志(bit flags),每个标志的值都是2的幂(即只有一个位被设置为1),因此可以通过按位或 | 运算来组合多个事件。
2026-01-07 14:21:37
813
原创 【仿Muduo库项目】Buffer模块设计实现
另外,注意:_buffer是std::vector<char>类型,它的元素是char,所以begin()返回的是std::vector<char>::iterator,解引用后得到char,然后取地址得到char*。这样的设计带来了显著的优势:即使一次读取的数据量不足以构成一个完整的应用层数据包,这些数据也可以安全地暂存在Buffer中,等待后续数据的到达。:如果后面空间不足,但前面有可回收空间(已被读取的数据空间),系统会将现有的有效数据整体移动到缓冲区起始位置,腾出连续的大块空间。
2026-01-06 14:48:56
581
原创 【仿Muduo库项目】基础套件实现
在C++中,std::function是一个通用的函数包装器,它可以存储、复制和调用任何可调用对象(如函数、lambda表达式、绑定表达式、函数对象等)。下面我将详细说明如何使用std::function。包含头文件定义一个std::functionstd::function<返回类型(参数类型列表)> 对象名;示例示例1:无参数无返回值的函数// 普通函数1:无参数无返回值// 创建function对象并赋值普通函数// 调用function对象myFunc();
2026-01-03 18:03:40
826
原创 【仿Muduo库项目】项目简介
目录一.我们的项目做了什么二.Reactor 模式(事件驱动处理模式)2.1.餐厅里的Reactor模式2.2.Reactor的由来2.1.单 Reactor 单进程 / 线程 2.2.单 Reactor 多线程 / 多进程2.3.多 Reactor 多进程 / 线程(主从 Reactor 模型)三.模块划分3.1.SERVER模块3.1.1. Buffer模块3.1.2. Socket模块3.1.3.Channel模块3.1.4.Connection模块3.1.5.Acceptor模块3.1.6.Time
2026-01-01 15:04:39
1001
原创 【消息队列项目】服务器实现
在这个模块,我们需要制定好我们的网络通信协议,那么由于我们使用的是Muduo库来进行数据的传输,那么Muduo库里面进行数据传输的时候,Muduo库它自己内部已经定制好了一个传输协议。事实上,仅仅只是上面那个协议还是不行的,Muduo库就基于上面那个格式来接着定义了下面这么一个通信协议。我们服务器的代码都是存放在下面的broker.hpp里面的。这个大家自己看看就行了,我们接下来来设计我们的服务器。具体的实现过程在code.cc里面,我们可以看看。我们这个类里面的成员主要包含下面这些。
2025-12-28 10:55:02
549
原创 【消息队列项目】连接管理模块实现
注意我们的代码都是存放在下面这个connection.hpp里面的// Connection类:管理单个TCP连接,提供信道的创建、关闭和查询功能public:// 智能指针别名,便于资源管理// 构造函数:初始化连接所需的各个组件Connection(const VirtualHost::ptr &host, // 虚拟机主机环境const ConsumerManager::ptr &cmp, // 消费者管理器。
2025-12-23 21:27:12
1063
原创 【消息队列项目】消费者管理模块实现
客户端这边每当发起一个订阅请求,意味着服务器这边就多了一个订阅者(处理消息的客户端描述),而这个消费者或者说订阅者它是和队列直接关联的,因为订阅请求中会描述当前用户想要订阅哪一个队列的消息。该系统负责维护所有消费者的状态、其与队列的订阅关系,并实现消息的公平分发。而一个信道关闭的时候,或者队列被删除的时候,那么这个信道或队列关联的消费者 也就没有存在的意义了,因此也需要将相关的消费者信息给删除掉。它将根据当前的轮转序号,从列表中选取一个消费者(轮询方式),并更新序号,然后返回该消费者信息。
2025-12-22 22:34:35
590
原创 【消息队列项目】路由交换模块实现
绑定键(Binding Key)存在于交换机和队列的绑定信息中由数字、字母、下划线组成。使用英文句点(.)将字符串分隔成多个独立的单词(Segment)。允许在独立的单词中使用通配符 *(星号)和 #(井号)来定义模式。路由键(Routing Key)存在于消息中由数字、字母、下划线组成。使用英文句点(.)分隔成多个具体的单词。不允许使用任何通配符,它必须是一个明确的路径。英文句号的作用英文句点 . 是唯一的分隔符,用于将整个键(Key)划分为多个逻辑部分,我们称这些部分为“单词”。
2025-12-22 16:50:00
988
原创 【消息队列项目】虚拟机管理实现
注意,我们这个虚拟机的代码都是放在下面的queue.hpp里面的。四个数据管理模块,并依据数据间的关联关系提供联合操作支持。那么按照上面的思路,我们很快就能写出虚拟机的框架。这样子,我们很快就能写出下面这个代码。创建交换机,队列,绑定,消息测试。我们很快就能写出下面这个测试。很简单就能写出下面这个代码。删除交换机,队列测试。完美,一点错误都没有。
2025-12-21 18:03:48
331
原创 【消息队列项目】交换机数据管理实现,队列数据管理实现
我们交换机的所有类,都存放在mqserver/exchange.hpp里面好了,我们现在开始设计。
2025-12-13 10:34:11
983
原创 【消息队列项目】公共模块实现
1. body 是对象本身body是一个std::string类型的对象,而read函数需要的是char*指针。所以直接使用body会导致类型不匹配,编译错误。2. body.c_str() 返回的是const char*c_str()函数返回一个指向以空字符结尾的字符数组的指针,即C风格的字符串。这个指针是const char*,意味着我们不能通过这个指针修改字符串的内容。而read函数需要向这个缓冲区写入数据,所以不能使用const char*。3. &body[0] 返回的是char*
2025-12-12 17:38:22
916
原创 【消息队列项目】项目详细设计方案
一个队列如果持久化标志为false,则意外着重启后,队列没了,也没有客户端能订阅队列的信息,因此这个队列的消息如果持久化存储,是没有意义的,因此应该队列的持久化标志是false,那么它的消息也不需要持久化。为了能充分的利用资源,因此对通信连接有进行了进一步的细化,细化出了通信通道,对于用户来说,一个通信通道,就是进行网络通信的载体,而一个真正的通信连接,可以创建出多个通信通道。由于垃圾回收会改变消息在文件中的位置,该结构需要在垃圾回收后更新对应消息的存储偏移量(仅更新已持久化的消息)。
2025-12-09 20:17:41
993
原创 【消息队列项目】C++11 异步操作实现线程池
你可以把 std::async 想象成一个帮你“外包任务”的聪明管家。你:就是主线程,正在处理主要工作(比如做菜)。任务:一件你想完成,但又不想自己停下来去做的耗时工作(比如去楼下买瓶酱油)。你把这个买酱油的任务“外包”给了他。管家不会立刻把酱油给你,而是给你一张“收据”或一个“承诺”。这张收据上写着“未来会有一瓶酱油”。这张收据就是 std::future 对象。现在,关键来了:这个管家派谁去执行“买酱油”这个任务呢?这取决于你给他的指令,也就是 std::launch 启动策略。
2025-12-07 10:58:04
706
原创 【消息队列项目】GTest简介
目录一.宏1.1.TEST 宏1.2.TEST_F 宏二.断言三.事件机制3.1.全局事件3.2.TestSuite事件3.3.TestCase事件3.4.TestSuite事件和TestCase事件混合使用GTest 是一个跨平台的 C++单元测试框架,由google公司发布。gtest是为了在不同平台上为编写C++单元测试而生成的。它提供了丰富的断言、致命和非致命判断、参数化等等场景1:你写了一个计算器函数没有 GTest 时:问题: 代码很乱,每次改代码都要手动测试,容易漏测有 GTest
2025-12-06 13:53:07
814
原创 【消息队列项目】Muduo库的介绍
首先,我们想要了解Muduo库的运行过程,我们需要先了解一些基础知识在C++中,std::function是一个通用的函数包装器,它可以存储、复制和调用任何可调用对象(如函数、lambda表达式、绑定表达式、函数对象等)。下面我将详细说明如何使用std::function。包含头文件定义一个std::functionstd::function<返回类型(参数类型列表)> 对象名;示例示例1:无参数无返回值的函数// 普通函数1:无参数无返回值// 创建function对象并赋值普通函数。
2025-12-05 00:08:00
1061
原创 【消息队列项目】项目简介以及环境准备
我们放弃了从零开始编写原生Socket的方案,因为其复杂度高,需要处理粘包、拆包、连接管理等一系列繁琐问题。最终选择基于。
2025-12-01 10:17:03
735
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅