标签:
Acceptor类:
类成员:
class Acceptor : boost::noncopyable { public: typedef boost::function<void (int sockfd, const InetAddress&)> NewConnectionCallback; Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); ~Acceptor(); void setNewConnectionCallback(const NewConnectionCallback& cb) { newConnectionCallback_ = cb; } bool listenning() const { return listenning_; } void listen(); private: //调用accept()接受新连接,并回调用户callback void handleRead(); EventLoop* loop_; //此socket是listen socket Socket acceptSocket_; //channel对象观察上述socket上的readable事件,并回调handleRead() Channel acceptChannel_; NewConnectionCallback newConnectionCallback_; bool listenning_; int idleFd_; };
//构造函数调用socket() 、bind(),即创建TCP服务端的传统步骤 //socket() bind() listen()任何一个步骤出错都会造成程序终止,故没有错误处理 //sockets::createNonblockingOrDie创建非阻塞的socket Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) : loop_(loop), acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), acceptChannel_(loop, acceptSocket_.fd()), listenning_(false), idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) { assert(idleFd_ >= 0); acceptSocket_.setReuseAddr(true); acceptSocket_.setReusePort(reuseport); acceptSocket_.bindAddress(listenAddr); acceptChannel_.setReadCallback( boost::bind(&Acceptor::handleRead, this)); } //调用listen(),当socket可读时调用handleRead() void Acceptor::listen() { loop_->assertInLoopThread(); listenning_ = true; acceptSocket_.listen(); acceptChannel_.enableReading(); } //accept策略 //参考acceptable strategies for improving web server performance void Acceptor::handleRead() { loop_->assertInLoopThread(); InetAddress peerAddr; //FIXME loop until no more int connfd = acceptSocket_.accept(&peerAddr); if (connfd >= 0) { // string hostport = peerAddr.toIpPort(); // LOG_TRACE << "Accepts of " << hostport; if (newConnectionCallback_) { newConnectionCallback_(connfd, peerAddr); } else { sockets::close(connfd); } } else { LOG_SYSERR << "in Acceptor::handleRead"; // Read the section named "The special problem of // accept()ing when you can‘t" in libev‘s doc. // By Marc Lehmann, author of livev. //本进程的文件描述符已经达到上限,由于没有socket文件描述符来表示这个连接,就无法close它.若epoll_wait是LT,则每次调用都会立刻返回,因为新连接还等待处理 //准备一个空闲的文件描述符,在这种情况下,先关闭这个空闲的fd,然后accept拿到新socket连接的描述符,随后close它,再重新打开一个空闲文件给该空闲文件描述符 if (errno == EMFILE) { ::close(idleFd_); idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); ::close(idleFd_); idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); } } }
TcpServer类:管理accept获得的TcpConnection.TcpServer是供用户直接使用的,生命期由用户控制.
TCP网络库:Acceptor、TcpServer、TcpConnection
标签:
原文地址:http://www.cnblogs.com/ljygoodgoodstudydaydayup/p/5666952.html