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