Acceptor类
Accept类中包含一个Channel类的对象、一个Socket类的对象(与Accept类均为组合关系),并记录了该Channel对象所属的EventLoop。
Acceptor类的构造函数
在构造函数中,主要完成了4件事:
1.创建监听套接字(即创建Socket类的对象)
2.注册IO事件(即创建Channel类的对象)
3.在::bind之前调用::setsockopt设置SO_REUSEADDR套接字选项(一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,才可以重复绑定使用。server程序总是应该在调用::bind之前设置SO_REUSEADDR)
4.在构造函数函数体中,调用::bind,并通过Channel::setReadCallback设置读事件回调函数
调用顺序:
EventLoop::loop–>EventLoop::loop中调用Poller::poll(多态)返回活跃的Channel对象–>调用Channel::handleEvent–>在Channel::handleEvent中,由于监听事件是读事件,所以调用读事件回调函数(这里通过Channel对象调用Channel::setReadCallback将Acceptor::handleRead设置为读事件回调函数)–>在Acceptor::handleRead中,除了调用::accept外,还调用了应用层回调函数 newConnectionCallback_(typedef boost::function<void (int sockfd,const InetAddress&)> NewConnectionCallback;
)。
注意,应用层回调函数 Acceptor::newConnectionCallback_(这里已经在TcpServer类的构造函数中调用Acceptor::setNewConnectionCallback将应用层回调函数newConnectionCallback_设置为TcpServer::newConnection)。
Acceptor::listen
这是Acceptor类最重要的对外接口函数:
该函数主要完成了3件事:
1.设置监听状态标志位为true
2.调用::listen
3.调用 Channel::enableReading 注册可读事件(即把监听事件挂到epoll的红黑树上去)
数据成员int idleFd_
这是一个空闲的文件描述符,为了防止文件描述符过多,达到服务端可接受的最大连接数的情况,处理::accept失败的情况。具体细节见源码,很简单。
源码
Acceptor.h
// This is an internal header file, you should not include this.
#ifndef MUDUO_NET_ACCEPTOR_H
#define MUDUO_NET_ACCEPTOR_H
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <muduo/net/Channel.h>
#include <muduo/net/Socket.h>
namespace muduo
{
namespace net
{
class EventLoop;
class InetAddress;
///
/// Acceptor of incoming TCP connections.
///
class Acceptor : boost::noncopyable
{
public:
typedef boost::function<void (int sockfd,
const InetAddress&)> NewConnectionCallback;
Acceptor(EventLoop* loop, const InetAddress& listenAddr