提取muduo库核心功能,去除boost依赖

用C++11提供的一些新特性重写了muduo网络库的核心功能,去除了对boost库的依赖

源码地址

https://gitee.com/to-the-sea/mymuduo

muduo网络库的reactor模型

在这里插入图片描述

Muduo网络库采用的是多Reactor模型。Reactor模式是一个并发处理IO事件的基本模式,将IO事件通知给应用程序处理。而多Reactor模型则是将多个Reactor运行在不同的线程中,可以更好地利用多核CPU,提高网络服务的并发能力。

在Muduo网络库中,每个线程都有一个EventLoop对象,EventLoop中维护了一个EpollPoller对象和Channel对象列表。EpollPoller使用epoll多路复用技术来监听和处理IO事件,Channel则负责将IO事件分发到对应的事件处理函数中。多个线程同时运行时,每个线程都会处理自己的IO事件,这样就能够充分利用多核CPU,提高网络服务的并发能力。

具体的实现方式是,Muduo网络库中的每个线程都有一个EventLoop对象,这个对象负责监听和处理该线程中的所有IO事件。当IO事件发生时,EpollPoller会通知对应的Channel对象,Channel对象再将事件分发给对应的事件处理函数。而在主线程中,还有一个Acceptor对象,负责监听新连接的到来。当有新的连接到来时,Acceptor会将新连接的文件描述符通知给SubReactor线程,由SubReactor线程负责处理新连接。

在这个多Reactor模型中,有一个主Reactor和多个SubReactor。主Reactor只负责监听新连接的到来,不处理其他的IO事件;而每个SubReactor都负责监听和处理自己的IO事件。这样可以避免IO事件的处理被阻塞,提高网络服务的响应速度。

Muduo网络库的多Reactor模型可以充分利用多核CPU,提高网络服务的并发能力,避免IO事件的处理被阻塞,提高网络服务的响应速度。同时,该模型设计简单,易于实现和维护。

muduo网络库的分层设计

整个网络库分为四个层次,自下而上分别是网络层、IO复用层、事件分发层、应用层。

  • 网络层
    网络层主要是对网络编程的一些封装,包括Socket、Address、Connection等类。其中Socket类是对socket文件描述符的一些封装,封装了socket的各种操作,如创建socket、绑定地址、监听、接受连接等。Address类是对网络地址的封装,可以通过构造函数传入ip和端口号,也可以通过调用getAddress函数获取对端的地址信息。Connection类是对连接的一些封装,包括读写数据、关闭连接等。
  • IO复用层
    IO复用层主要负责对IO复用的一些封装,包括Poller、Channel、EpollPoller等类。其中Poller类是对IO多路复用的封装,抽象了IO多路复用的操作,如注册事件、删除事件等。Channel类是对文件描述符的封装,每个Channel对象与一个文件描述符对应,其中定义了该文件描述符可以监听的事件、事件的回调函数等。EpollPoller类是对epollIO多路复用的封装,继承自Poller类,重写了一些函数,实现了epoll IO多路复用的功能。
  • 事件分发层
    事件分发层主要是对事件的一些封装,包括EventLoop、EventLoopThread、EventLoopThreadPool等类。其中EventLoop类是事件循环类,负责接收Channel对象上的事件并将其分发到对应的事件处理函数中。EventLoopThread类是封装了一个新线程,并在该线程上创建一个EventLoop对象,用于处理事件。EventLoopThreadPool类是封装了一个线程池,用于创建一组EventLoopThread对象,以此提高并发处理能力。
  • 应用层
    包括TcpConnection、TcpServer、TcpClient等类。其中TcpConnection类是对一条TCP连接的封装,包括读写数据、关闭连接等。TcpServer类是对TCP服务器的封装,负责监听并处理新的连接。TcpClient类是对TCP客户端的封装,负责与服务器建立连接。

muduo网路库中的Buffer类

Buffer是muduo网络库中非常重要的一个类,它封装了数据缓冲区,实现了高效的读写操作。在网络编程中,数据通常是以流的形式进行传输的,而Buffer类的作用就是把接收到的数据流存储到缓冲区中,以便进行后续的处理。同时,在发送数据时,Buffer类也会把待发送的数据先存储到缓冲区中,等待发送完成的通知。

Buffer类中主要包含了以下几个成员变量:

std::vector buffer_:使用STL中的vector容器来存储数据;
size_t readerIndex_:表示缓冲区中当前已经读取的数据的位置;
size_t writerIndex_:表示缓冲区中当前已经写入的数据的位置;
static const char kCRLF[]:表示回车换行符;
static const size_t kCheapPrepend:表示预留的空间大小;
static const size_t kInitialSize:表示初始缓冲区大小。
Buffer类中提供了一系列的公共方法,例如:读写数据、移动数据、判断缓冲区是否为空等等。其中,最重要的方法是readableBytes()和writableBytes()方法,它们用来获取当前可读数据的大小和可写空间的大小。另外,Buffer类还提供了peek()方法,用于读取缓冲区中某个位置的数据,但并不修改缓冲区的读写位置。

Buffer类采用了一些先进的技术来提高读写操作的效率。其中最重要的技术是缓存区分片,即将缓存区按照一定的规则划分成多个连续的区域,每个区域的大小都是固定的。在数据读写时,可以通过这种方式避免频繁地进行内存分配和释放,从而提高读写操作的效率。此外,Buffer类还使用了std::copy()函数来复制数据,而不是采用循环遍历的方式,进一步提高了数据读写的效率。

另外,Buffer类还采用了引用计数的技术,即在多个Buffer对象之间共享同一个底层缓存区,避免了内存复制和资源浪费。Buffer类中使用了std::shared_ptr<std::vector>来管理缓存区的生命周期,保证缓存区在所有Buffer对象都被销毁后才会被释放。这种设计方式不仅提高了内存的利用率,也避免了因为多次内存分配和释放导致的内存碎片问题。

总之,Buffer类是muduo网络库中非常重要的一个类,它实现了高效的读写操作,采用了先进的技术来提高读写操作的效率,并且除了前面介绍的内容,Buffer类还实现了一些其他的功能,例如支持字符串和文件的读写。

当需要从Buffer中读取数据时,可以调用retrieve()方法。该方法会返回Buffer中的读取位置和未读取数据的长度。可以将返回的长度作为参数传递给recv()方法,从Socket中读取相应长度的数据,并将数据追加到Buffer中。

当需要将数据写入Buffer中时,可以调用append()方法。该方法会将数据追加到Buffer的末尾,并调用wakeup()方法唤醒IO线程,使其开始处理写事件。当Buffer中的数据被写入Socket中后,Buffer会自动调整其读取位置,丢弃已经写入Socket的数据。

另外,Buffer还支持对Buffer中的数据进行查找和截取等操作。例如,可以使用findCRLF()方法查找Buffer中的"\r\n"字符,并返回其在Buffer中的位置。

Buffer类所使用的技术包括了std::vector和readv/writev函数。std::vector是C++ STL中的一个动态数组容器,可以自动扩展和收缩内存空间。Buffer类将其作为底层实现,使用其动态扩展和收缩内存空间的特性,以及对连续内存块的支持,来管理Buffer中的数据。

而readv/writev函数则是Linux系统中的系统调用,可以在一次调用中读取或写入多个不连续的内存块。Buffer类使用readv/writev函数来将数据读入Buffer或从Buffer中写入Socket,避免了多次调用read/write函数的开销,提高了IO的效率。

muduo网络库使用eventfd进行mainReactor和subReactor之间的通信

在Muduo网络库中,使用EventFd来唤醒SubReactor的事件循环。EventFd是一个事件文件描述符,它的原理是在内核中创建了一个eventfd对象,当我们向这个对象写入一个64位无符号整型数时,就会触发该事件,从而唤醒在该对象上等待的进程或线程。

在Muduo网络库中,MainReactor和SubReactor之间的通信需要使用EventFd实现,具体流程如下:

  1. 在MainReactor中创建一个EventFd对象,用于唤醒SubReactor的事件循环。
  2. 将EventFd对象封装成Channel对象,并注册到subReactor的Epoll对象中。
  3. 当需要唤醒SubReactor的事件循环时,MainReactor会向EventFd对象写入一个64位无符号整型数,这时EventFd就会触发事件,SubReactor会从eventfd中读取这个值,从而被唤醒。
  4. 当SubReactor被唤醒后,会处理掉所有已经就绪的Channel对象,然后重新进入事件循环等待下一次事件触发。

通过使用EventFd来唤醒SubReactor,Muduo网络库实现了MainReactor和SubReactor之间的高效通信,避免了使用轮询或者信号等方式带来的额外开销和延迟。同时,这也是一种高效的线程间通信方式,可以广泛应用于多线程编程场景中。

C++是一种面向对象的计算机程序设计语言,由美国AT&T贝尔实验室的本贾尼·斯特劳斯特卢普博士在20世纪80年代初期发明并实现(最初这种语言被称作“C with Classes”带类的C)。它是一种静态数据类型检查的、支持多重编程范式的通用程序设计语言。它支持过程化程序设计、数据抽象、面向对象程序设计、泛型程序设计等多种程序设计风格。 图片 C++是C语言的继承,进一步扩充和完善了C语言,成为一种面向对象的程序设计语言。C++这个词在中国大陆的程序员圈子中通常被读做“C加加”,而西方的程序员通常读做“C plus plus”,“CPP”。 在C基础上,一九八三年又由贝尔实验室的Bjarne Strou-strup推出了C++C++进一步扩充和完善了C语言,成为一种面向 对象的程序设计语言。C++目前流行的编译器最新版本是Borland C++ 4.5,Symantec C++ 6.1,和Microsoft Visual C++ 2012。C++提出了一些更为深入的概念,它所支持的这些面向对象的概念容易将问题空间直接地映射到程序空间,为程序员提供了一种与传统结构程序设计不同的思维方式和编程方法。因而也增加了整个语言的复杂性,掌握起来有一定难度。 图片 C++由美国AT&T贝尔实验室的本贾尼·斯特劳斯特卢普博士在20世纪80年代初期发明并实现(最初这种语言被称作“C with Classes”带类的C)。开始,C++是作为C语言的增强版出现的,从给C语言增加类开始,不断的增加新特性。虚函数(virtual function)、运算符重载(Operator Overloading)、多重继承(Multiple Inheritance)、模板(Template)、异常(Exception)、RTTI、命名空间(Name Space)逐渐被加入标准。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值