muduo的Channel类剖析
来源:互联网 发布:中老年品位 知乎 编辑:程序博客网 时间:2024/05/22 06:17
Channel类,即通道类。
>它是muduo库负责注册读写事件的类,并保存了fd读写事件发生时调用的回调函数,如果poll/epoll有读写事件发生则将这些事件添加到对应的通道中。
>一个通道对应唯一EventLoop,一个EventLoop可以有多个通道。
>Channel类不负责fd的生存期,fd的生存期是有socket决定的,断开连接关闭描述符。
>当有fd返回读写事件时,调用提前注册的回调函数处理读写事件
下面是源码解析:
#ifndef MUDUO_NET_CHANNEL_H#define MUDUO_NET_CHANNEL_H#include <boost/function.hpp>#include <boost/noncopyable.hpp>#include <boost/shared_ptr.hpp>#include <boost/weak_ptr.hpp>#include <muduo/base/Timestamp.h>namespace muduo{namespace net{class EventLoop;////// A selectable I/O channel.////// This class doesn't own the file descriptor./// The file descriptor could be a socket,/// an eventfd, a timerfd, or a signalfdclass Channel : boost::noncopyable{ public: typedef boost::function<void()> EventCallback; //事件回调处理 typedef boost::function<void(Timestamp)> ReadEventCallback; //读事件的回调处理,传一个时间戳 Channel(EventLoop* loop, int fd); //一个Channel一个EventLoop ~Channel(); void handleEvent(Timestamp receiveTime); //处理事件 void setReadCallback(const ReadEventCallback& cb) //设置各种回调函数 { readCallback_ = cb; } void setWriteCallback(const EventCallback& cb) { writeCallback_ = cb; } void setCloseCallback(const EventCallback& cb) { closeCallback_ = cb; } void setErrorCallback(const EventCallback& cb) { errorCallback_ = cb; }#ifdef __GXX_EXPERIMENTAL_CXX0X__ void setReadCallback(ReadEventCallback&& cb) { readCallback_ = std::move(cb); } void setWriteCallback(EventCallback&& cb) { writeCallback_ = std::move(cb); } void setCloseCallback(EventCallback&& cb) { closeCallback_ = std::move(cb); } void setErrorCallback(EventCallback&& cb) { errorCallback_ = std::move(cb); }#endif /// Tie this channel to the owner object managed by shared_ptr, /// prevent the owner object being destroyed in handleEvent. void tie(const boost::shared_ptr<void>&); //与TcpConnection有关,防止事件被销毁。 int fd() const { return fd_; } //描述符 int events() const { return events_; } //注册的事件 void set_revents(int revt) { revents_ = revt; } // used by pollers // int revents() const { return revents_; } bool isNoneEvent() const { return events_ == kNoneEvent; } //判断是否无关注事件类型,events为0 void enableReading() { events_ |= kReadEvent; update(); } //或上事件,就是关注可读事件,注册到EventLoop,通过它注册到Poller中 void disableReading() { events_ &= ~kReadEvent; update(); } //取消关注 void enableWriting() { events_ |= kWriteEvent; update(); } //关注可写事件 void disableWriting() { events_ &= ~kWriteEvent; update(); } //关闭 void disableAll() { events_ = kNoneEvent; update(); } //全部关闭 bool isWriting() const { return events_ & kWriteEvent; } //是否关注了写 bool isReading() const { return events_ & kReadEvent; } //是否关注读 // for Poller int index() { return index_; } //pollfd数组中的下标 void set_index(int idx) { index_ = idx; } // for debug string reventsToString() const; //事件转化为字符串,方便打印调试 string eventsToString() const; //同理 void doNotLogHup() { logHup_ = false; } EventLoop* ownerLoop() { return loop_; } void remove(); //移除,确保调用前调用disableall。 private: static string eventsToString(int fd, int ev); void update(); void handleEventWithGuard(Timestamp receiveTime); static const int kNoneEvent; //三个常量,没有事件,static常量类外部有定义,在.cc文件中 static const int kReadEvent; //可读事件 static const int kWriteEvent; //可写事件 EventLoop* loop_; //记录所属EventLoop const int fd_; //文件描述符,但不负责关闭改描述符 int events_; //关注的时间类型 int revents_; // it's the received event types of epoll or poll int index_; // used by Poller.,表示在Poller事件数组中的序号 bool logHup_; //for POLLHUP boost::weak_ptr<void> tie_; //负责生存期控制 bool tied_; bool eventHandling_; //是否处于处理事件中 bool addedToLoop_; ReadEventCallback readCallback_; //几种事件处理回调 EventCallback writeCallback_; EventCallback closeCallback_; EventCallback errorCallback_;};}}#endif // MUDUO_NET_CHANNEL_H
.cc文件:
#include <muduo/base/Logging.h>#include <muduo/net/Channel.h>#include <muduo/net/EventLoop.h>#include <sstream>#include <poll.h>using namespace muduo;using namespace muduo::net;const int Channel::kNoneEvent = 0; //集中事件类型定义const int Channel::kReadEvent = POLLIN | POLLPRI; //PRI比如TCP的带外数据const int Channel::kWriteEvent = POLLOUT;Channel::Channel(EventLoop* loop, int fd__) : loop_(loop), fd_(fd__), events_(0), revents_(0), index_(-1), logHup_(true), tied_(false), eventHandling_(false), addedToLoop_(false){}Channel::~Channel(){ assert(!eventHandling_); assert(!addedToLoop_); if (loop_->isInLoopThread()) { assert(!loop_->hasChannel(this)); }}void Channel::tie(const boost::shared_ptr<void>& obj){ tie_ = obj; tied_ = true;}void Channel::update() //更新事件类型{ addedToLoop_ = true; loop_->updateChannel(this); //调用loop的,loop再调用poll的注册pollfd}void Channel::remove() //移除{ assert(isNoneEvent()); addedToLoop_ = false; loop_->removeChannel(this);}void Channel::handleEvent(Timestamp receiveTime) //事件到来调用handleEvent处理{ boost::shared_ptr<void> guard; if (tied_) { guard = tie_.lock(); if (guard) { handleEventWithGuard(receiveTime); } } else { handleEventWithGuard(receiveTime); }}void Channel::handleEventWithGuard(Timestamp receiveTime){ eventHandling_ = true; LOG_TRACE << reventsToString(); if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) //判断返回事件类型 { if (logHup_) //如果有POLLHUP事件,输出警告信息 { LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP"; } if (closeCallback_) closeCallback_(); //调用关闭回调函数 } if (revents_ & POLLNVAL) //不合法文件描述符,并没有终止,因为服务器程序要保证一天二十四小时工作。 { LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL"; } if (revents_ & (POLLERR | POLLNVAL)) { if (errorCallback_) errorCallback_(); } if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) //POLLRDHUP是对端关闭连接事件,如shutdown等 { if (readCallback_) readCallback_(receiveTime); } if (revents_ & POLLOUT) { if (writeCallback_) writeCallback_(); } eventHandling_ = false; //处理完了=false}string Channel::reventsToString() const{ return eventsToString(fd_, revents_);}string Channel::eventsToString() const{ return eventsToString(fd_, events_);}string Channel::eventsToString(int fd, int ev) //调试输出发生了什么事件{ std::ostringstream oss; oss << fd << ": "; if (ev & POLLIN) oss << "IN "; if (ev & POLLPRI) oss << "PRI "; if (ev & POLLOUT) oss << "OUT "; if (ev & POLLHUP) oss << "HUP "; if (ev & POLLRDHUP) oss << "RDHUP "; if (ev & POLLERR) oss << "ERR "; if (ev & POLLNVAL) oss << "NVAL "; return oss.str().c_str();}
0 0
- muduo的Channel类剖析
- muduo channel 类
- muduo的Mutex类剖析
- muduo库的Timestamp类剖析
- muduo库的Singleton类剖析
- muduo库的ThreadLocal类剖析
- muduo库的ThreadLocalSingleton类剖析
- muduo库的PollPoller类剖析
- muduo库的EventLoop类剖析
- muduo库的EventLoopThread类剖析
- muduo库的Acceptor类剖析
- golang的channel剖析
- muduo库的ThreadPool剖析
- muduo库的AtomicIntegerT剖析
- muduo库的EpollPoller剖析
- muduo的http库剖析
- muduo库Thread类剖析
- muduo库的Condition类和CountDownLatch类剖析
- 图片查看器
- tomcat抛异常classNotFoundException:org.spring.framework.web.servlet.dispatcherServlet
- Butterknife全方位解析
- mysql主从复制配置(基于GTID)
- 程序员可以的8种境界
- muduo的Channel类剖析
- android4.4沉浸式状态栏总结
- 欢迎使用CSDN-markdown编辑器
- 进程创建关于fork()浅解
- Linux下的C语言编程——简单实现tcp客户端和服务器
- 理解线程3 c语言示例线程基本操作
- C语言编译的各个阶段
- 3. Longest Substring Without Repeating Characters
- Oracle进阶一