muduo源码解析25-网络库3:channel类最终版

channel类:

说明:

为了更好地管理channel,在channel中添加一些额外的成员变量/函数。使其和muduo源码一致

channel.h:

#ifndef CHANNEL_H
#define CHANNEL_H

#include"base/noncopyable.h"
#include"base/timestamp.h"

#include<memory>
#include<functional>

namespace mymuduo {

namespace net {

class eventloop;

class channel:noncopyable
{
public:
    typedef std::function<void()> EventCallback;
    typedef std::function<void(timestamp)> ReadEventCallback;

    channel(eventloop* loop,int fd);
    ~channel();

    //处理网络事件
    void handleEvent(timestamp recieve);
    //设置四个回调函数,read,write,close,error Callback函数,在处理event时被调用
    void setReadCallback(ReadEventCallback cb)
    { m_readCallback = std::move(cb); }
    void setWriteCallback(EventCallback cb)
    { m_writeCallback = std::move(cb); }
    void setCloseCallback(EventCallback cb)
    { m_closeCallback=std::move(cb);}
    void setErrorCallback(EventCallback cb)
    { m_errorCallback = std::move(cb); }

    void tie(const std::shared_ptr<void>&);

    int fd()const {return m_fd;}    //channel所负责IO事件的那个fd
    //返回当前channel所注册的网络事件
    int events() const{return m_events;}
    void set_revents(int revt){m_revents=revt;} //设置网络事件
    //判断当前channel是否注册了事件
    bool isNoneEvent() const{return m_events==kNoneEvent;}

    //在m_event上注册读/写事件
    void enableReading(){m_events|=kReadEvent;update();}
    void enableWriting(){m_events|=kWriteEvent;update();}
    //在m_event上取消读/写事件
    void disableReading(){m_events&=~kReadEvent;update();}
    void disableWriting(){m_events&=~kWriteEvent;update();}

    //取消m_event所有事件
    void disableAll(){m_events=kNoneEvent;update();}

    //判断m_event是否注册了读/写事件
    bool isWriting() const{return m_events & kWriteEvent;}
    bool isReading() const{return m_events & kWriteEvent;}

    //for poller,当前channel在poller::m_pollfds中的位置
    int index(){return m_index;}
    void set_index(int idx){m_index=idx;}


    //for debug
    string reventsToString()const;
    string eventsToString() const;
    //是否打印日志
    void doNotLogHup(){m_logHup=false;}

    //返回当前channel所在的那个eventloop
    eventloop* ownerLoop(){return m_loop;}
    //让eventloop移除自身这个channel
    void remove();

private:
    static string eventsToString(int fd,int ev);
    //让本channel 所属于的那个eventloop回调channel::update()完成channel的更新
    //实际上最终在poller中被更新
    void update();
    //在handleEvent()内部使用的具体的实现
    void handleEventWithGuard(timestamp receiveTime);
    //这三个静态常量分别表示:无网络事件,读网络事件,写网络事件
    static const int kNoneEvent;
    static const int kReadEvent;
    static const int kWriteEvent;

    eventloop* m_loop;  //channel所属的那个eventloop
    const int m_fd;     //每个channel负责处理一个sockfd上的网络事件
    int m_events;       //channel注册(要监听)的网络事件
    int m_revents;      //poll()返回的网络事件,具体发生的事件
    int m_index; //这个channel在poller中m_pollfds中的序号,默认-1表示不在其中
    bool m_logHup;  //是否打印日志

    std::weak_ptr<void> m_tie;      //???
    bool m_tied;            //
    bool m_eventHandling;   //是否正在处理网络事件
    bool m_addedToLoop;     //是否被添加到eventloop中执行
    //当发生了读/写/错误网络事件时,下面几个函数会被调用
    ReadEventCallback m_readCallback;
    EventCallback m_writeCallback;
    EventCallback m_closeCallback;
    EventCallback m_errorCallback;

};

}//namespace net

}//namespace mymuduo

#endif // CHANNEL_H

 

 

 

channel.cpp

#include "channel.h"

#include"base/logging.h"
#include"net/channel.h"
#include"net/eventloop.h"

#include<sstream>

#include<poll.h>


namespace mymuduo {

namespace net {

const int channel::kNoneEvent=0;
const int channel::kReadEvent=POLLIN|POLLPRI;
const int channel::kWriteEvent=POLLOUT;

//构造函数,根据sockfd创建一个对应的channel,仅初始化成员
channel::channel(eventloop* loop,int fd)
    :m_loop(loop),m_fd(fd),m_events(0),m_revents(0),m_index(-1),
      m_logHup(true),m_tied(false),m_eventHandling(false),m_addedToLoop(false)
{

}

//保证这个channel析构时,eventloop不再持有这个channel
channel::~channel()
{
    assert(!m_eventHandling);
    assert(!m_addedToLoop);
    if(m_loop->isInLoopThread())
        assert(!m_loop->hasChannel(this));
}

//此时eventloop::loop()中poll函数返回,说明有网络事件发生了,
//内部利用handleEventWithGuard()实现对各个网络事件的处理
void channel::handleEvent(timestamp receiveTime)
{
    std::shared_ptr<void> guard;
    if (m_tied)
    {
      guard = m_tie.lock();
      if (guard)
      {
        handleEventWithGuard(receiveTime);
      }
    }
    else
    {
      handleEventWithGuard(receiveTime);
    }
}

void channel::tie(const std::shared_ptr<void> &obj)
{
    m_tie=obj;
    m_tied=true;
}

//for debug
string channel::reventsToString()const
{
    return eventsToString(m_fd,m_revents);
}
string channel::eventsToString() const
{
    return eventsToString(m_fd,m_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();
}

//让eventloop删除这个channel
void channel::remove()
{
    assert(isNoneEvent());
    m_addedToLoop=false;
    m_loop->removeChannel(this);
}

//让本channel 所属于的那个eventloop回调channel::update()完成channel的更新
void channel::update()
{
    m_addedToLoop=true;
    m_loop->updateChannel(this);
}

//channel::handleEvent()的内部实现,根据不同的网络事件调用不同的回调处理
void channel::handleEventWithGuard(timestamp receiveTime)
{
    m_eventHandling = true;
    LOG_TRACE << reventsToString();
    //处理关闭事件
    if ((m_revents & POLLHUP) && !(m_revents & POLLIN))
    {
      if (m_logHup)
      {
        LOG_WARN << "fd = " << m_fd << " Channel::handle_event() POLLHUP";
      }
      if (m_closeCallback) m_closeCallback();
    }

    if (m_revents & POLLNVAL)
    {
      LOG_WARN << "fd = " << m_fd << " Channel::handle_event() POLLNVAL";
    }

    //处理错误事件
    if (m_revents & (POLLERR | POLLNVAL))
    {
      if (m_errorCallback) m_errorCallback();
    }
    //处理读网络事件
    if (m_revents & (POLLIN | POLLPRI | POLLRDHUP))
    {
      if (m_readCallback) m_readCallback(receiveTime);
    }
    //处理写网络事件
    if (m_revents & POLLOUT)
    {
      if (m_writeCallback) m_writeCallback();
    }
    m_eventHandling = false;
}

}//namespace net

}//namespace mymuduo

 

注意:析构函数中调用eventloop::hasChannel()和remove函数中eventloop::removeChannel()目前还没有在eventloop类中实现,这里先说一下,他们的作用就是判断当前channel是否在eventloop中,以及让在eventloop中移除这个channel

 

posted @ 2020-09-01 20:43  WoodInEast  阅读(217)  评论(0编辑  收藏  举报