26muduo_net库源码分析(二)

来源:互联网 发布:医生收入 知乎 编辑:程序博客网 时间:2024/06/12 21:01

1.类图

2.Channel

(1)Channelselectable IO channel,负责注册与响应IO事件,它不拥有filedescriptor
(2)ChannelAcceptorConnectorEventLoopTimerQueueTcpConnection的成员,生命期由后者控制。

3.时序图



4.代码

EvevtLoop.h

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is a public header file, it must only include public header files.#ifndef MUDUO_NET_EVENTLOOP_H#define MUDUO_NET_EVENTLOOP_H#include <vector>#include <boost/noncopyable.hpp>#include <boost/scoped_ptr.hpp>#include <muduo/base/CurrentThread.h>#include <muduo/base/Thread.h>#include <muduo/base/Timestamp.h>namespace muduo{namespace net{class Channel;class Poller;////// Reactor, at most one per thread.////// This is an interface class, so don't expose too much details.class EventLoop : boost::noncopyable{ public:  EventLoop();  ~EventLoop();  // force out-line dtor, for scoped_ptr members.  ///  /// Loops forever.  ///  /// Must be called in the same thread as creation of the object.  ///  void loop();  void quit();  ///  /// Time when poll returns, usually means data arrivial.  ///  Timestamp pollReturnTime() const { return pollReturnTime_; }  // internal usage  void updateChannel(Channel* channel);// 在Poller中添加或者更新通道  void removeChannel(Channel* channel);// 从Poller中移除通道  void assertInLoopThread()  {    if (!isInLoopThread())    {      abortNotInLoopThread();    }  }  bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }  static EventLoop* getEventLoopOfCurrentThread(); private:  void abortNotInLoopThread();  void printActiveChannels() const; // DEBUG  typedef std::vector<Channel*> ChannelList;    bool looping_; /* atomic */  bool quit_; /* atomic */  bool eventHandling_; /* atomic */  const pid_t threadId_;// 当前对象所属线程ID  Timestamp pollReturnTime_;  boost::scoped_ptr<Poller> poller_;  ChannelList activeChannels_;// Poller返回的活动通道  Channel* currentActiveChannel_;// 当前正在处理的活动通道};}}#endif  // MUDUO_NET_EVENTLOOP_H

EventLoop.cc

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/EventLoop.h>#include <muduo/base/Logging.h>#include <muduo/net/Channel.h>#include <muduo/net/Poller.h>//#include <poll.h>using namespace muduo;using namespace muduo::net;namespace{// 当前线程EventLoop对象指针// 线程局部存储__thread EventLoop* t_loopInThisThread = 0;const int kPollTimeMs = 10000;}EventLoop* EventLoop::getEventLoopOfCurrentThread(){  return t_loopInThisThread;}EventLoop::EventLoop()  : looping_(false),    quit_(false),    eventHandling_(false),    threadId_(CurrentThread::tid()),poller_(Poller::newDefaultPoller(this)),currentActiveChannel_(NULL){  LOG_TRACE << "EventLoop created " << this << " in thread " << threadId_;  // 如果当前线程已经创建了EventLoop对象,终止(LOG_FATAL)  if (t_loopInThisThread)  {    LOG_FATAL << "Another EventLoop " << t_loopInThisThread              << " exists in this thread " << threadId_;  }  else  {    t_loopInThisThread = this;  }}EventLoop::~EventLoop(){  t_loopInThisThread = NULL;}// 事件循环,该函数不能跨线程调用// 只能在创建该对象的线程中调用void EventLoop::loop(){  assert(!looping_);  // 断言当前处于创建该对象的线程中  assertInLoopThread();  looping_ = true;  LOG_TRACE << "EventLoop " << this << " start looping";  //::poll(NULL, 0, 5*1000);  while (!quit_)  {    activeChannels_.clear();    pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);    //++iteration_;    if (Logger::logLevel() <= Logger::TRACE)    {      printActiveChannels();    }    // TODO sort channel by priority    eventHandling_ = true;    for (ChannelList::iterator it = activeChannels_.begin();        it != activeChannels_.end(); ++it)    {      currentActiveChannel_ = *it;      currentActiveChannel_->handleEvent(pollReturnTime_);    }    currentActiveChannel_ = NULL;    eventHandling_ = false;    //doPendingFunctors();  }  LOG_TRACE << "EventLoop " << this << " stop looping";  looping_ = false;}void EventLoop::quit(){  quit_ = true;  if (!isInLoopThread())  {    //wakeup();  }}void EventLoop::updateChannel(Channel* channel){  assert(channel->ownerLoop() == this);  assertInLoopThread();  poller_->updateChannel(channel);}void EventLoop::removeChannel(Channel* channel){  assert(channel->ownerLoop() == this);  assertInLoopThread();  if (eventHandling_)  {    assert(currentActiveChannel_ == channel ||        std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end());  }  poller_->removeChannel(channel);}void EventLoop::abortNotInLoopThread(){  LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this            << " was created in threadId_ = " << threadId_            << ", current thread id = " <<  CurrentThread::tid();}void EventLoop::printActiveChannels() const{  for (ChannelList::const_iterator it = activeChannels_.begin();      it != activeChannels_.end(); ++it)  {    const Channel* ch = *it;    LOG_TRACE << "{" << ch->reventsToString() << "} ";  }}

Channel.h

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is an internal header file, you should not include this.#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();  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; }  /// 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>&);  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; }  void enableReading() { events_ |= kReadEvent; update(); }  // 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; }  // for Poller  int index() { return index_; }  void set_index(int idx) { index_ = idx; }  // for debug  string reventsToString() const;  void doNotLogHup() { logHup_ = false; }  EventLoop* ownerLoop() { return loop_; }  void remove(); private:  void update();  void handleEventWithGuard(Timestamp receiveTime);  static const int kNoneEvent;  static const int kReadEvent;  static const int kWriteEvent;  EventLoop* loop_;// 所属EventLoop  const int  fd_;// 文件描述符,但不负责关闭该文件描述符  int        events_;// 关注的事件  int        revents_;// poll/epoll返回的事件  int        index_;// used by Poller.表示在poll的事件数组中的序号  bool       logHup_;// for POLLHUP  boost::weak_ptr<void> tie_;  bool tied_;  bool eventHandling_;// 是否处于处理事件中  ReadEventCallback readCallback_;  EventCallback writeCallback_;  EventCallback closeCallback_;  EventCallback errorCallback_;};}}#endif  // MUDUO_NET_CHANNEL_H

Channel.cc

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#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;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){}Channel::~Channel(){  assert(!eventHandling_);}void Channel::tie(const boost::shared_ptr<void>& obj){  tie_ = obj;  tied_ = true;}void Channel::update(){  loop_->updateChannel(this);}// 调用这个函数之前确保调用disableAllvoid Channel::remove(){  assert(isNoneEvent());  loop_->removeChannel(this);}void Channel::handleEvent(Timestamp receiveTime){  boost::shared_ptr<void> guard;  if (tied_)  {    guard = tie_.lock();    if (guard)    {      handleEventWithGuard(receiveTime);    }  }  else  {    handleEventWithGuard(receiveTime);  }}void Channel::handleEventWithGuard(Timestamp receiveTime){  eventHandling_ = true;  if ((revents_ & POLLHUP) && !(revents_ & POLLIN))  {    if (logHup_)    {      LOG_WARN << "Channel::handle_event() POLLHUP";    }    if (closeCallback_) closeCallback_();  }  if (revents_ & POLLNVAL)  {    LOG_WARN << "Channel::handle_event() POLLNVAL";  }  if (revents_ & (POLLERR | POLLNVAL))  {    if (errorCallback_) errorCallback_();  }  if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))  {    if (readCallback_) readCallback_(receiveTime);  }  if (revents_ & POLLOUT)  {    if (writeCallback_) writeCallback_();  }  eventHandling_ = false;}string Channel::reventsToString() const{  std::ostringstream oss;  oss << fd_ << ": ";  if (revents_ & POLLIN)    oss << "IN ";  if (revents_ & POLLPRI)    oss << "PRI ";  if (revents_ & POLLOUT)    oss << "OUT ";  if (revents_ & POLLHUP)    oss << "HUP ";  if (revents_ & POLLRDHUP)    oss << "RDHUP ";  if (revents_ & POLLERR)    oss << "ERR ";  if (revents_ & POLLNVAL)    oss << "NVAL ";  return oss.str().c_str();}

Poller.h

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is an internal header file, you should not include this.#ifndef MUDUO_NET_POLLER_H#define MUDUO_NET_POLLER_H#include <vector>#include <boost/noncopyable.hpp>#include <muduo/base/Timestamp.h>#include <muduo/net/EventLoop.h>namespace muduo{namespace net{class Channel;////// Base class for IO Multiplexing////// This class doesn't own the Channel objects.class Poller : boost::noncopyable{ public:  typedef std::vector<Channel*> ChannelList;  Poller(EventLoop* loop);  virtual ~Poller();  /// Polls the I/O events.  /// Must be called in the loop thread.  virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0;  /// Changes the interested I/O events.  /// Must be called in the loop thread.  virtual void updateChannel(Channel* channel) = 0;  /// Remove the channel, when it destructs.  /// Must be called in the loop thread.  virtual void removeChannel(Channel* channel) = 0;  static Poller* newDefaultPoller(EventLoop* loop);  void assertInLoopThread()  {    ownerLoop_->assertInLoopThread();  } private:  EventLoop* ownerLoop_;// Poller所属EventLoop};}}#endif  // MUDUO_NET_POLLER_H

Poller.cc

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/Poller.h>using namespace muduo;using namespace muduo::net;Poller::Poller(EventLoop* loop)  : ownerLoop_(loop){}Poller::~Poller(){}

PollPoller.h

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is an internal header file, you should not include this.#ifndef MUDUO_NET_POLLER_POLLPOLLER_H#define MUDUO_NET_POLLER_POLLPOLLER_H#include <muduo/net/Poller.h>#include <map>#include <vector>struct pollfd;namespace muduo{namespace net{////// IO Multiplexing with poll(2).///class PollPoller : public Poller{ public:  PollPoller(EventLoop* loop);  virtual ~PollPoller();  virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels);  virtual void updateChannel(Channel* channel);  virtual void removeChannel(Channel* channel); private:  void fillActiveChannels(int numEvents,                          ChannelList* activeChannels) const;  typedef std::vector<struct pollfd> PollFdList;  typedef std::map<int, Channel*> ChannelMap;// key是文件描述符,value是Channel*  PollFdList pollfds_;  ChannelMap channels_;};}}#endif  // MUDUO_NET_POLLER_POLLPOLLER_H

PollPoller.cc

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/poller/PollPoller.h>#include <muduo/base/Logging.h>#include <muduo/base/Types.h>#include <muduo/net/Channel.h>#include <assert.h>#include <poll.h>using namespace muduo;using namespace muduo::net;PollPoller::PollPoller(EventLoop* loop)  : Poller(loop){}PollPoller::~PollPoller(){}Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels){  // XXX pollfds_ shouldn't change  int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);  Timestamp now(Timestamp::now());  if (numEvents > 0)  {    LOG_TRACE << numEvents << " events happended";    fillActiveChannels(numEvents, activeChannels);  }  else if (numEvents == 0)  {    LOG_TRACE << " nothing happended";  }  else  {    LOG_SYSERR << "PollPoller::poll()";  }  return now;}void PollPoller::fillActiveChannels(int numEvents,                                    ChannelList* activeChannels) const{  for (PollFdList::const_iterator pfd = pollfds_.begin();      pfd != pollfds_.end() && numEvents > 0; ++pfd)  {    if (pfd->revents > 0)    {      --numEvents;      ChannelMap::const_iterator ch = channels_.find(pfd->fd);      assert(ch != channels_.end());      Channel* channel = ch->second;      assert(channel->fd() == pfd->fd);      channel->set_revents(pfd->revents);      // pfd->revents = 0;      activeChannels->push_back(channel);    }  }}void PollPoller::updateChannel(Channel* channel){  Poller::assertInLoopThread();  LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();  if (channel->index() < 0)  {// index < 0说明是一个新的通道    // a new one, add to pollfds_    assert(channels_.find(channel->fd()) == channels_.end());    struct pollfd pfd;    pfd.fd = channel->fd();    pfd.events = static_cast<short>(channel->events());    pfd.revents = 0;    pollfds_.push_back(pfd);    int idx = static_cast<int>(pollfds_.size())-1;    channel->set_index(idx);    channels_[pfd.fd] = channel;  }  else  {    // update existing one    assert(channels_.find(channel->fd()) != channels_.end());    assert(channels_[channel->fd()] == channel);    int idx = channel->index();    assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));    struct pollfd& pfd = pollfds_[idx];    assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1);    pfd.events = static_cast<short>(channel->events());    pfd.revents = 0;// 将一个通道暂时更改为不关注事件,但不从Poller中移除该通道    if (channel->isNoneEvent())    {      // ignore this pollfd  // 暂时忽略该文件描述符的事件  // 这里pfd.fd 可以直接设置为-1      pfd.fd = -channel->fd()-1;// 这样子设置是为了removeChannel优化    }  }}void PollPoller::removeChannel(Channel* channel){  Poller::assertInLoopThread();  LOG_TRACE << "fd = " << channel->fd();  assert(channels_.find(channel->fd()) != channels_.end());  assert(channels_[channel->fd()] == channel);  assert(channel->isNoneEvent());  int idx = channel->index();  assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));  const struct pollfd& pfd = pollfds_[idx]; (void)pfd;  assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events());  size_t n = channels_.erase(channel->fd());  assert(n == 1); (void)n;  if (implicit_cast<size_t>(idx) == pollfds_.size()-1)  {    pollfds_.pop_back();  }  else  {// 这里移除的算法复杂度是O(1),将待删除元素与最后一个元素交换再pop_back    int channelAtEnd = pollfds_.back().fd;    iter_swap(pollfds_.begin()+idx, pollfds_.end()-1);    if (channelAtEnd < 0)    {      channelAtEnd = -channelAtEnd-1;    }    channels_[channelAtEnd]->set_index(idx);    pollfds_.pop_back();  }}