Muduo(C++11版本) 源码剖析(四)———Channel设计

Channel扮演了一个IO事件分发器的作用。主要有两个地方,一个是Acceptor中的Channel,主要处理连接事件,另外每个TcpConnection类中会有一个Channel,检测fd的刻可读,关闭,错误消息,触发相应的回调函数。生命周期由Acceptor和TcpConnection控制。

成员变量:

private:
                static const int            kNoneEvent;
		static const int            kReadEvent;
		static const int            kWriteEvent;
		EventLoop*                  loop_;
		const int                   fd_;
		int                         events_;
		int                         revents_; 
		int                         index_; 
		bool                        logHup_;
		std::weak_ptr         tie_;         
		bool                        tied_;
		//bool                        eventHandling_;
		//bool                        addedToLoop_;
		ReadEventCallback           readCallback_;
		EventCallback               writeCallback_;
		EventCallback               closeCallback_;
		EventCallback               errorCallback_;

kNoneEvent,KreadEvent,kWriteEvent是用于标记events_状态的值,loop是传入的所属的eventloop,fd_是创建通道时传入的文件描述符,events_是通道状态标记,revents_是多路复用检测后外部set的事件类型,tie用于延长对象的生命周期,readCallback,writeCallback,closeCallback,errorCallback则是注册的外部回调。

 

重要函数及作用:

创建

Channel::Channel(EventLoop* loop, int fd__): loop_(loop),
                                            fd_(fd__),
                                            events_(0),
                                            revents_(0),
                                            index_(-1),
                                            logHup_(true),
                                            tied_(false)/*,
                                            eventHandling_(false),
                                            addedToLoop_(false)
                                            */
{
}

因为一般网络库会把监听的scoket单独放在一个线程,然后连接到来的多个socket放在其他几个线程,所以就有了两个创建Channel的地方,一个是在Acceptor构造中创建用于监听socket的通道,一个是新连接到来TcpConnection中创建的Channel。构造函数中传入了当前所属的事件循环和文件fd。

 

注册回调

acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));

channel_->setReadCallback(std::bind(&TcpConnection::handleRead, this, std::placeholders::_1));
channel_->setWriteCallback(std::bind(&TcpConnection::handleWrite, this));
channel_->setCloseCallback(std::bind(&TcpConnection::handleClose, this));
channel_->setErrorCallback(std::bind(&TcpConnection::handleError, this));

前面说了,两个地方创建了Channel,所以回调也设置也不同,Acceptor中Channel回调指向了Acceptor的handle函数,进而指向了TcpServer的newconnetion(),而TcpConnection中Channel则是回调到了TcpConnection中。

 

处理事件

void Channel::handleEvent(Timestamp receiveTime)
{
	std::shared_ptr guard;
	if (tied_)
	{
		guard = tie_.lock();
		if (guard)
		{
			handleEventWithGuard(receiveTime);
		}
	}
	else
	{
		handleEventWithGuard(receiveTime);
	}
}

void Channel::handleEventWithGuard(Timestamp receiveTime)
{
	LOGD(reventsToString().c_str());
	if ((revents_ & XPOLLHUP) && !(revents_ & XPOLLIN))
	{
		if (logHup_)
		{
			LOGW("Channel::handle_event() XPOLLHUP");
		}
		if (closeCallback_) closeCallback_();
	}

	if (revents_ & XPOLLNVAL)
	{
		LOGW("Channel::handle_event() XPOLLNVAL");
	}

	if (revents_ & (XPOLLERR | XPOLLNVAL))
	{
		if (errorCallback_) 
            errorCallback_();
	}
    
	if (revents_ & (XPOLLIN | XPOLLPRI | XPOLLRDHUP))
	{
		//当是侦听socket时,readCallback_指向Acceptor::handleRead
        //当是客户端socket时,调用TcpConnection::handleRead 
        if (readCallback_) 
            readCallback_(receiveTime);
	}

	if (revents_ & XPOLLOUT)
	{
		//如果是连接状态服的socket,则writeCallback_指向Connector::handleWrite()
        if (writeCallback_) 
            writeCallback_();
	}
	//eventHandling_ = false;
}

handleEvent中tie实际上这是一个弱指针,指向向他的拥有者TcpConnection,为什么要这么做呢?假如Channel正在处理事件,TcpConnection连接关闭销毁了,程序可能会dump,要保证TcpConnection不被销毁,因此Channel中存了一个TcpConnection的弱指针,在处理事件的时候,lock将引用计数加1保证TcpConnection不被销毁。

handleEventWithGuard根据revents_不同的值调用不同的回调函数,revents_的值是在Poll(IO多路复用类)设置的,由Poll检测是什么事件,给revents_赋相应的值,处理不同的事件。

 

 

你可能感兴趣的:(c++,Muduo网络库剖析)