• 【MUDUO 】Channel通道


    Reactor模型图 

     

    目前 TcpServer 类需要封装的两个类, 一个是事件循环类 ,一个是IP地址端口打包类,IP地址打包的类封装完。

    而EventLoop 下还需要两个重要类:一个是channel通道类,一个是poller抽象类

    现在我们需要的补上TcpServer类 EventLoop类

    TcpServer.h

    对外使用编程服务器的类

    1. #pragma once
    2. class TcpServer
    3. {
    4. public:
    5. private:
    6. };

    EventLoop.h

    事件循环类 主要包含了两大模块, channel poller(epoll的抽象,muduo库中也实现了poll) 

    1. #pragma once
    2. class EventLoop
    3. {
    4. public:
    5. private:
    6. };

    Channel.h

    EventLoop、Channel、Poller之间的关系 是EventLoop 包含了它两, Readctor模型上的Demultipex

    channel 理解为通道,封装了sockfd和其感兴趣的event, 如EPOLLIN、EPOLLOUT事件。 还绑定了poller返回的事件

    Channel的成员变量:

    1. static const int kNoneEvent;            没有对任何事件感兴趣

    2. static const int kReadEvent;              对读事件感兴趣

    3. static const int kWriteEvent;              对写事件感兴趣

    4. EventLoop *loop_;                             事件循环

    5. const int fd_;                                       fd, poller监听的对象

    6. int events_;                                         注册fd感兴趣的事件

    7. int revents_;                                        poller返回具体发生的事件

    8. int index_;

    9. std::weak_ptr tie_;                   绑定的自己

    10. bool tied_;                                          

    11. ReadEventCallback readCallback_;  用户注册的读回调

    12. EventCallback writeCallback_;          用户注册的写回调

    13. EventCallback closeCallback_;         用户注册的关闭回调

    14. EventCallback errorCallback_;          用户注册的错误回调

    1. #pragma once
    2. #include
    3. #include
    4. #include "noncopyable.h"
    5. #include "Timestamp.h"
    6. //头文件里边只用了类型的声明,没有用到类型具体的定义以及方法,所以我们在这头文件中就只需要一些前置声明一下就好
    7. class EventLoop;
    8. class Channel:public noncopyable
    9. {
    10. public:
    11. //绑定回调函数
    12. using EventCallback = std::function<void()>;
    13. using ReadEventCallback = std::function<void(Timestamp)>;
    14. //因为是指针都是4字节,不影响编译,所以前置声明就好了
    15. Channel(EventLoop *loop, int fd);
    16. ~Channel();
    17. //这个Timestamp需要计算类大小,所以不能只做前置声明
    18. //fd得到poller通知以后,处理事件,调用相应的回调方法
    19. void handleEvent(Timestamp receiveTime);
    20. //设置回调
    21. void setReadCallback(ReadEventCallback cb)
    22. {
    23. readCallback_ = std::move(cb);
    24. }
    25. void setWriteCallback(EventCallback cb)
    26. {
    27. writeCallback_ = std::move(cb);
    28. }
    29. void setCloseCallback(EventCallback cb)
    30. {
    31. closeCallback_ = std::move(cb);
    32. }
    33. void setErrorCallback(EventCallback cb)
    34. {
    35. errorCallback_ = std::move(cb);
    36. }
    37. //防止channel被remove掉,channel还在执行回调
    38. void tie(const std::shared_ptr<void>& );
    39. int fd()const { return fd_; }
    40. int events() const { return events_; }
    41. //设置fd事件,因为是poller监听的,所以需要对外提供一个接口去设置
    42. int set_revents(int rev) { events_ = rev ; }
    43. //设置fd相应的时间状态,也就是给epoll_ctl 设置
    44. void enableReading() { events_ |= kReadEvent; update(); }
    45. void disableReading() { events_ &= ~kReadEvent; update(); }
    46. void enableWriting() { events_ |= kWriteEvent; update();}
    47. void disableWriting() { events_ &= ~kWriteEvent; update();}
    48. void disableAll() { events_ = kNoneEvent; update(); }
    49. //判断是否对任何事件都不感兴趣
    50. bool isNoneEvent() const { return events_ == kNoneEvent; }
    51. bool isWriting() const { return events_ & kWriteEvent; }
    52. bool isReading() const { return events_ & kReadEvent; }
    53. int index() { return index_; }
    54. void set_index(int idx) { index_ = idx; }
    55. //当前channel属于哪个eventLoop,一个EventLoop有很多个channel,一个线程一个EventLoop
    56. EventLoop* ownerLoop() { return loop_; }
    57. void remove();
    58. private:
    59. void update();
    60. void handleEventWithhGuard(Timestamp receiveTime);
    61. private:
    62. //表示FD的一个状态
    63. static const int kNoneEvent;
    64. static const int kReadEvent;
    65. static const int kWriteEvent;
    66. //事件循环
    67. EventLoop *loop_;
    68. const int fd_;
    69. int events_;
    70. int revents_;
    71. int index_;
    72. //弱智能指针
    73. std::weak_ptr<void> tie_;
    74. bool tied_;
    75. //channel能获知fd最终发生的具体事件revents,所以它负责调用具体事件的回调操作
    76. ReadEventCallback readCallback_;
    77. EventCallback writeCallback_;
    78. EventCallback closeCallback_;
    79. EventCallback errorCallback_;
    80. };

    Channel.cc 

    1. #include "Channel.h"
    2. #include "EventLoop.h"
    3. #include "Logger.h"
    4. #include
    5. const int Channel::kNoneEvent = 0;
    6. const int Channel::kReadEvent = EPOLLIN | EPOLLPRI;
    7. const int Channel::kWriteEvent = EPOLLOUT;
    8. Channel::Channel(EventLoop *loop, int fd)
    9. :loop_(loop),fd_(fd),events_(0),revents_(0),index_(-1),tied_(false)
    10. {}
    11. Channel::~Channel(){}
    12. //channel里的tie方法什么时候被调用过? 后边再看
    13. void Channel::tie(const std::shared_ptr<void> &obj)
    14. {
    15. tie_ = obj; //绑定成弱智能指针观察强智能指针
    16. tied_ = true;//绑定过了就置成true
    17. }
    18. /**
    19. * @brief 当改变channel所表示fd的events事件后,update负责在poller里面更改fd相应的时间epoll_ctl
    20. *
    21. * poller在哪呢? poller 跟channel是两个不同的模块。因为epoll不属于channel管,但是他们两都是数据EventLoop的
    22. *
    23. * EventLoop 包含了ChannelList"也就是一个channel列表", 和一个poller
    24. *
    25. * 所以channel本身想向Channel注册fd对应的事件是做不了的,因为它又没有poller对象,所以需要通过EventLoop来做这件事情
    26. *
    27. */
    28. void Channel::update()
    29. {
    30. //通过Channel所属的EventLoop,调用poller的相应方法,注册fd的Events事件
    31. //add code
    32. //loop_->updateChannel(this);
    33. }
    34. //在channel所属的EventLoop中的容器,把自己给删除掉
    35. void Channel::remove()
    36. {
    37. //add code
    38. // loop_->removeChannel(this);
    39. }
    40. //fd得到poller通知以后,处理事件的
    41. void Channel::handleEvent(Timestamp receiveTime)
    42. {
    43. if(tied_)
    44. {
    45. std::shared_ptr<void> guard = tie_.lock();
    46. if(guard)
    47. {
    48. handleEventWithhGuard(receiveTime);
    49. }
    50. }
    51. else
    52. {
    53. handleEventWithhGuard(receiveTime);
    54. }
    55. }
    56. //根据poller通知的channel发生的具体事件,由channel负责调用具体的回调操作
    57. void Channel::handleEventWithhGuard(Timestamp receiveTime)
    58. {
    59. LOG_INFO("channel handleEvent revent:%d\n", revents_);
    60. if((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN))
    61. {
    62. if(closeCallback_)
    63. {
    64. closeCallback_();
    65. }
    66. }
    67. //事件发生错误
    68. if(revents_ & EPOLLERR)
    69. {
    70. if(errorCallback_)
    71. {
    72. errorCallback_();
    73. }
    74. }
    75. //可读事件
    76. if(revents_ & (EPOLLIN | EPOLLPRI))
    77. {
    78. if(readCallback_)
    79. {
    80. readCallback_(receiveTime);
    81. }
    82. }
    83. if(revents_ & EPOLLOUT)
    84. {
    85. if(writeCallback_)
    86. {
    87. writeCallback_();
    88. }
    89. }
    90. }

    channel.cc 中还有三个遗留问题:

    1.  void Channel::update() :下次补全方法
    2. void Channel::remove():下次补全方法

    3. 看看后边tie方法什么时候被调用过? 因为它触发了之后才会触发void Channel::handleEvent里边的弱智能指针的提升

  • 相关阅读:
    canvas的基本使用
    编译器做了这么多,你知道吗?
    解密JavaChassis3:易扩展的多种注册中心支持
    机器人系统 ROS 常用命令行工具
    网络安全:常见的中间件以及环境搭建方法
    动态内存(进阶四)
    SpringMVC(JSR303和拦截器)
    JavaScript数据类型学习脑图
    云计算基础技术
    java毕业设计在线售药系统Mybatis+系统+数据库+调试部署
  • 原文地址:https://blog.csdn.net/weixin_40533189/article/details/125863566