Muduo::acceptor, TCPServer Analysis

Source: Internet
Author: User

Acceptor

The class acceptor is used to listen, accept, and call the callback function to handle the new connection. The socket FD is encapsulated in the acceptor, which is initialized with the RAII technique. After accept, if a new connection arrives, the Handleread () function is called, and the connection is received in this function. Each time a new connection is received in the Handleread () function, the callback function (if any) that handles the new connection is called, but there may be multiple connections at once, and one of the improvements here is: loop accept, until no new connection arrives, or every time you accept, try to receive N.
In Handleread (), the accept does not consider whether the new connection is available, such as when the file descriptor is exhausted. Here can make an improvement, after receiving the CONNFD after the accept, if greater than 0, then non-blocking poll (2), see if you can read and write, normally will be writable, indicating CONNFD available; if poll (2) returns an error, close CONNFD directly.

Acceptor.h

Class acceptor:boost::noncopyable{ Public: typedef boost::function<void(intSOCKFD,Constinetaddress&) > Newconnectioncallback;function object called after//acceptAcceptor (eventloop* Loop,Constinetaddress& Listenaddr,BOOLReuseport); ~acceptor ();voidSetnewconnectioncallback (Constnewconnectioncallback& cb) {newconnectioncallback_ = cb;}BOOLListenning ()Const{returnListenning_; }voidListen ();Private:void Handleread();  eventloop* Loop_;  Socket acceptsocket_;  Channel Acceptchannel_; Newconnectioncallback Newconnectioncallback_;BOOLListenning_;//Is listening on state  intIdlefd_;};

acceptor.cc

Acceptor::acceptor (eventloop* Loop,Constinetaddress& Listenaddr,BOOLReuseport): Loop_ (Loop), acceptsocket_ (Sockets::createnonblockingordie ()),//Initialize creation of Sockt FDAcceptchannel_ (Loop, acceptsocket_. FD()),//Initialize channelListenning_ (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));callback function is called when FD is readable hanleread}acceptor::~acceptor () {Acceptchannel_. Disableall();//Poller it to be removed in the listener collection, this is the kdeleted stateAcceptchannel_. Remove();//Remove it from EventList events_, this is the knew State:: Close (idlefd_);}voidAcceptor::listen () {loop_->assertinloopthread (); Listenning_ =true; Acceptsocket_. Listen(); Acceptchannel_. enablereading();}voidAcceptor::handleread () {loop_->assertinloopthread (); InetAddress peeraddr;//fixme Loop until no more  intCONNFD = acceptsocket_. Accept(&AMP;PEERADDR);//Here when really receive connection  if(CONNFD >=0)  {//String hostport = Peeraddr.toipport ();    //Log_trace << "accepts of" << Hostport;    if(Newconnectioncallback_) {Newconnectioncallback_ (CONNFD, peeraddr);//Transfer the new connection information to the callback function}Else///No callback function closes client-corresponding FD{sockets::close (CONNFD); }  }Else{Log_syserr <<"in Acceptor::handleread";//Read The section named "The Special problem of    //accept () ing when your can ' t ' in Libev ' s doc.    //By Marc Lehmann, author of Livev.    if(errno = = emfile)      {:: Close (Idlefd_); Idlefd_ =:: Accept (acceptsocket_. FD(),NULL,NULL);      :: Close (Idlefd_); Idlefd_ =:: Open ("/dev/null", O_rdonly |    O_CLOEXEC); }  }}
TCPServer

The customer does not directly use acceptor, which is encapsulated in the TCPServer. TCPServer is simple to use, directly set the new connection arrival and message arrival callback function, and then start.
The Eventloopthreadpool is also encapsulated in the TCPServer, so the EventLoop object in TCPServer is the main reactor,eventloopthreadpool for Sub Reactor.
When the new connection arrives, TCPServer creates a new Tcpconnection object to hold the connection, sets the callback function for the new connection, Then take a EventLoop object in Eventloopthreadpool as the reactor for this new connection.
TCPServer saves the tcpconnection in the current server object with a map, and when the TCPServer object is refactored, all connections are closed.

TcpServer.h

Class tcpserver:boost::noncopyable{ Public: typedef boost::function<void(eventloop*) > Threadinitcallback;enumOption {knoreuseport, Kreuseport,};//tcpserver (eventloop* loop, const inetaddress& LISTENADDR);TCPServer (eventloop* Loop,Constinetaddress& Listenaddr,Const string& namearg, option option = Knoreuseport); ~tcpserver ();//Force Out-line Dtor, for SCOPED_PTR members.  Const string& Hostport ()Const{returnHostport_; }Const string& Name ()Const{returnname_; } eventloop* Getloop ()Const{returnLoop_; }///Set The number of   threads for handling input.  ///  //Always   accepts new connection in loop ' s thread.  //   must be called before @c start  //   @param numthreads    ///-0 means all I/O in loop ' s thread, no thread would created.  ///This is the   default value.    ///-1 means all I/O in another thread.    //-n means a thread pool with N threads, new connections  //Is   assigned on a round-robin basis.  voidSetthreadnum (intNumthreads);voidSetthreadinitcallback (Constthreadinitcallback& cb) {threadinitcallback_ = cb;}  //valid after calling start ()Boost::shared_ptr<eventloopthreadpool> ThreadPool () {returnThreadpool_; }//   starts the server if it ' s not listenning.  ///  //   It ' s harmless to call it multiple times.  ///   Thread safe.  voidStart ();///   Set connection callback.  //Not   thread safe.  voidSetconnectioncallback (Constconnectioncallback& cb) {connectioncallback_ = cb;}///   Set message callback.  //Not   thread safe.  voidSetmessagecallback (Constmessagecallback& cb) {messagecallback_ = cb;}//   Set write complete callback.  //Not   thread safe.  voidSetwritecompletecallback (Constwritecompletecallback& cb) {writecompletecallback_ = cb;}Private://Not thread safe, butinchLoopvoid newconnection(intSOCKFD,Constinetaddress& peeraddr);///   Thread safe.  voidRemoveconnection (Consttcpconnectionptr& conn);//tcpconnectionptr to Shared_ptr<tcpconnection>  //Not   thread safe, but in loop  voidRemoveconnectioninloop (Consttcpconnectionptr& conn); typedef std::map<string, tcpconnectionptr> Connectionmap; eventloop* Loop_;//The acceptor loop  Const stringHostport_;Const stringname_; Boost::scoped_ptr<acceptor> Acceptor_;//Avoid revealing acceptorBoost::shared_ptr<eventloopthreadpool> Threadpool_; Connectioncallback Connectioncallback_;//callback function when a new connection arrivesMessagecallback Messagecallback_;//callback function when message arrivesWritecompletecallback Writecompletecallback_;  Threadinitcallback Threadinitcallback_; AtomicInt32 Started_;//Always in loop thread  intNextconnid_;//used to calculate the name of the tag connectionConnectionmap Connections_;//map Key is the name of connection};

tcpserver.cc

Tcpserver::tcpserver (eventloop* Loop,Constinetaddress& Listenaddr,Const string& namearg, option option): Loop_ (Check_notnull (Loop)), Hostport_ (Listenaddr.toipport ()), n Ame_ (Namearg), Acceptor_ (NewAcceptor (loop, listenaddr, option = Kreuseport)), Threadpool_ (NewEventloopthreadpool (Loop, name_)), Connectioncallback_ (Defaultconnectioncallback), Messagecallback_ ( Defaultmessagecallback), Nextconnid_ (1) {Acceptor_->setnewconnectioncallback (when a new connection arrives, the Tcpserver::newconnection function is calledBoost::bind (&tcpserver::newconnection, This, _1, _2));}  Tcpserver::~tcpserver () {loop_->assertinloopthread (); Log_trace <<"Tcpserver::~tcpserver ["<< name_ <<"] destructing"; for(Connectionmap::iterator It (Connections_.begin ());//Destroy connection in destructorIt! = Connections_.end ();    ++it) {Tcpconnectionptr conn = it->second;    It->second.reset ();    Conn->getloop ()->runinloop (Boost::bind (&tcpconnection::connectdestroyed, conn));  Conn.reset (); }}voidTcpserver::setthreadnum (intNumthreads)//Set thread pool size{assert(0<= numthreads); Threadpool_->setthreadnum (numthreads);}voidTcpserver::start () {if(Started_.getandset (1) ==0) {Threadpool_->start (threadinitcallback_);//Start thread pool    assert(!acceptor_->listenning ()); Loop_->runinloop (Boost::bind (&acceptor::listen, Get_pointer (ACCEPTOR_)));//Execute the Listen of the Accept}}voidTcpserver::newconnection (intSOCKFD,Constinetaddress& peeraddr) {loop_->assertinloopthread (); eventloop* Ioloop = Threadpool_->getnextloop ();///Online pool fetch a EventLoop object  Charbuf[ +]; snprintf (buf, sizeof buf,":%s#%d", Hostport_.c_str (), nextconnid_);//Generate the name of this connection++nextconnid_;stringConnname = name_ + buf; Log_info <<"Tcpserver::newconnection ["<< name_ <<"]-New Connection ["<< Connname <<"] from"<< Peeraddr.toipport (); InetAddress localaddr (Sockets::getlocaladdr (SOCKFD));//Fixme poll with zero timeout to double confirm the new connection  //Fixme use make_shared if necessaryTcpconnectionptr Conn (NewTcpconnection (Ioloop, Connname, SOCKFD,  LOCALADDR, peeraddr));  CONNECTIONS_[CONNNAME] = conn; Conn->setconnectioncallback (Connectioncallback_);//Set callback function for new connectionConn->setmessagecallback (Messagecallback_);  Conn->setwritecompletecallback (Writecompletecallback_); Conn->setclosecallback (Boost::bind (&tcpserver::removeconnection, This, _1));//Fixme:unsafeIoloop->runinloop (Boost::bind (&tcpconnection::connectestablished, conn));//Add incoming connections to listener events}voidTcpserver::removeconnection (Consttcpconnectionptr& conn) {//Fixme:unsafeLoop_->runinloop (Boost::bind (&tcpserver::removeconnectioninloop, This, conn));}voidTcpserver::removeconnectioninloop (Consttcpconnectionptr& conn) {loop_->assertinloopthread (); Log_info <<"Tcpserver::removeconnectioninloop ["<< name_ <<"]-Connection"<< Conn->name (); size_t n = connections_.erase (Conn->name ());//Remove connection According to connection's name(void) n;assert(n = =1);  eventloop* Ioloop = Conn->getloop (); Ioloop->queueinloop (Boost::bind (&tcpconnection::connectdestroyed, conn));}

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Muduo::acceptor, TCPServer Analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.