muduo网络库学习之EventLoop(一):事件循环类图简介

番外

TCP网络编程本质 

TCP网络编程最本质是的处理三个半事件

连接建立:服务器accept(被动)接受连接,客户端connect(主动)发起连接

连接断开:主动断开(close、shutdown),被动断开(read返回0)

消息到达:文件描述符可读

消息发送完毕:这算半个。对于低流量的服务,可不必关心这个事件;这里的发送完毕是指数据写入操作系统缓冲区,将由TCP协议栈负责数据的发送与重传,不代表对方已经接收到数据。

什么都不做的EventLoop

one loop per thread意思是说每个线程最多只能有一个EventLoop对象。

EventLoop对象构造的时候,会检查当前线程是否已经创建了其他EventLoop对象,如果已创建,终止程序(LOG_FATAL)

EventLoop构造函数会记住本对象所属线程(threadId_)。

创建了EventLoop对象的线程称为IO线程,其功能是运行事件循环(EventLoop::loop)


类图


白色部分是外部类,对外可见,灰色部分是内部类,对外不可见

EventLoop是事件循环的抽象,Poller是I/O复用的抽象,有两个派生类,分别封装poll和epoll,这个地方是muduo库唯一使用面向对象编程风格封装的

EventLoop与Poller的关系是组合,一个EventLoop包含一个Poller,并且Poller的生存期由EventLoop来控制,EventLoop是调用Poller的poll()函数实现的

Channel是对事件的注册与响应的封装,Channel的update()函数负责注册和更新I/O的可读、可写事件,Channel的handleEvent()成员函数对所发生的I/O事件进行处理。当调用update()函数注册和更新I/O的可读、可写事件的时候,又会调用到EventLoop的updateChannel(),从而又调用了Poller的updateChannel(),相当于将Channel注册到Poller中或者将fd_文件描述符的一些可读可写事件注册到Poller中。

一个Eventloop包含多个Channel,也就是说可以用来捕捉多个通道的可读可写事件,两者之间是聚合关系,也就是说EventLoop不负责Channel的生存期的控制。Channel的生存期的控制由TcpConnection、Acceptor、Connector等等这些类来控制

Channel不拥有文件描述符,意思就是当Channel对象销毁的时候不关闭文件描述符。它和文件描述符(不是一个类)的关系是关联关系,一个Channel有一个FileDescriptor,一个EventLoop有多个FileDescriptor,用来监听多个FileDescriptor的相关事件,这个FileDescriptor是被套接字所拥有的,也就是说生存期由套接字来控制,当套接字销毁,文件描述符销毁,套接字类的析构函数调用close()

Channel是TcpConnection、Acceptor、Connector的成员,关系也是组合,生存期由这些类控制,Acceptor是对被动连接的抽象,它关注的是监听套接字的可读事件,监听套接字的可读事件由Channel来注册,然后调用handleEvent(),从而又调用了Acceptor中的handRead(),这就是基于对象的编程思想,回调了handRead(),而不是在Channel中包含一个handRead(),然后由Acceptor继承下来。一旦监听套接字的可读事件(注册由Channel来完成发生,就回调handRead()来响应。Connector的handleWrite()和handleError也是由Channel来注册,Connector()是对主动连接的抽象。一旦被动连接或者主动连接建立之后,就会得到一个已连接套接字,已连接套接字的抽象就是TcpConnection,它会关注一些事件

Acceptor的生存期由TcpServer来控制,Connector的生存期由TcpClient来控制。TcpServer与TcpConnection的关系是聚合,一个TcpServer包含多个TcpConnection,但是不控制TcpConnection的生存期,因为有可能客户端关闭了连接,TcpConnection对象也要跟着销毁,而TcpServer对象并不销毁,对于TcpClient也是同样的道理。

时序图

猜你喜欢

转载自blog.csdn.net/wk_bjut_edu_cn/article/details/80856873
今日推荐