使用C++动手实现自己的网络库(参考Muduo)

使用C++动手实现自己的网络库(参考Muduo)

github网址:https://github.com/shiyu-ren/mymuduo

整体架构与Reactor架构

高并发时代,支持一个strong的网络服务器一定要是多核多线程的。libev作者说过:one loop per thread is usually a good model,这样多线程服务器的关键就在于如何设计一个高效易于使用的event loop,然后使用线程池去高效的利用线程去run这个event loop,来实现高性能服务器。 整体架构即为one loop per thread + threadpool。架构如下图
整体架构

那么在loop中,处理网络事件是需要高性能的网络组件的,其中你nonblocking + IO-Multiplexing是最经常使用的方案,因为使用IO-Multiplexing可以在单个线程中的单个loop中处理多个I/O,而同时,要想正确的使用IO-Multiplexing是必须要使用nonblocking I/O的,因为IO-Multiplexing使用blocking I/O的话,read/write/accept/connect都有可能阻塞当前线程,这样线程无法处理其他socket数据,在某些情况下会导致整个程序阻塞。
而具体实现这个EventLoop中的NonBlocking IO + IO Multiplexing是通过Reactor架构实现的,Reactor架构使得事件的处理变为异步,虽然对于编程者理解起来会困难一点,但是处理事件变得十分高效,是事件驱动,采取大量回调操作来处理事件。
Reactor的重要组件由:Event事件、Reactor反应堆、Demultiplex事件分发器、Evanthandler事件处理器
框架图如下:
Reactor

各个组件

Channel
主要是负责一个fd,以及各类事件及对应事件的回调)。他相当于Epoll反映堆模型中的自定义结构体。两种Channel(listenfd-accptorChannel(由Accptor给回调), connfd-connChannel(由TcpConnection给回调))
Poller
封装了IO-Multiplexing的操作
含有ChannelMap<int,Channel*>,经过poller后通过Map找到对应的Channel,返回给Loop的activateChannel。Channel与Poller通过EventLoop进行互相操作
EventLoop
EventLoop循环,调用Poller获取事件,再交给Channel处理事件
ChannelList activateChannels;//用于获取Poller所就绪的fd对应的Channel
//一个loop一个wakeupfd,负责主loop对工作loop进行唤醒
int wakeupfd;
std::unique_ptr wakeupChannel;
vector pendingFunctors
Thread与EventLoopThread
EventLoopThreadPool
getNextLoop()通过轮询获取下一个subloop
一个Thread对应一个Loop
Muduo的设计很多是尽可能的不用同步互斥,所以很多东西只要保证不是全局的就行,所以有很多操作转到InLoop执行就会比较安全
注意这里Muduo没有使用经典的生产者消费者模型去做线程池,而是通过Eventfd去将阻塞着的线程唤醒,这样在处理网络时会更加高效。
另外在底层Thread中创建Loop时需要进行同步操作,在线程中生成loop对象的栈变量时,要返回给EventLoopThread,此时需要进行同步操作,使用的是自己实现的CountDownLatch作为同步器
Socket
封装fd
Acceptor
封装了listenfd的各种操作
Buffer
应用写数据=》缓冲区=》Tcp发送缓冲区=》Send
|prependable | readerIdx | writerIdx
Muduo中Buffer有一个小技巧是,起初时分配大小并不分配很大,以免连接很多将内存撑爆。而是在读数据时准备一个栈上的内存,通过readv将数据读入Buffer与栈上的内存中,如果用到了栈上的这点内存,在将其append到Buffer上,这样可以不用起始分配很大的内存给Buffer,也可保证有足够的空间接受数据,可扩容。
TcpConnection
TcpConnection是有TcpServer创建,当有新连接到来时进行创建,负责连接两端的读写等操作
一个连接成功的客户端对应一个TcpConnection
unique_ptr Socket
unique_ptr channel
各种回调(由用户给TcpServer设置,TcpServer再给TcpConnection设置)
这里要注意写要比读难以实现,因为一次写的时候不一定可以把数据写完,这时候要将没写完的送到输出缓冲区中,并注册EPOLLOUT,使得Channel对写事件感兴趣,并再回调中处理这些没有发完的数据。但要注意写过后应该立马关掉EPOLLOUT,因为LT模式会一直上报。
TcpServer
TcpServer负责拥有Acceptor,当连接来时再建立TCPConenction,管理这两类对象。
Acceptor EventLoopThreadPoll
ConnectionMap connections
TimerQueue
定时器Muduo是使用底层是红黑树的set来管理的,而定时事件Muduo是使用Timerfd,将定时事件也变为一个IO事件,可以使用EventLoop统一管理

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值