muduo/net/Acceptor.h
muduo/net/Acceptor.cc
//用RAII方法封装socket file descriptor
muduo/net/Socket.h
muduo/net/Socket.cc
//封装了socket相关系统调用(全局函数,位于muduo::net::sockets名称空间中)
muduo/net/SocketsOps.h
muduo/net/SocketsOps.cc
//封装了字节序转换函数(全局函数,位于muduo::net::sockets名称空间中)
muduo/net/Endian.h
Acceptor用于accept接收TCP连接。
Acceptor的数据成员包括Socket、Channel,Acceptor的Socket是listening socket(即server socket)。
Channel 用于观察此Socket的readable事件,并回调Acceptor::handleRead(),handleRead()调用accept()来接收新连接,,并回调用户callback函数。
Acceptor是内部类,共TcpServer使用。
下面是一个使用示例
如果有client连接,回调函数向client发送“how are you?”字符串。
#include <muduo/net/Acceptor.h> #include <muduo/net/EventLoop.h> #include <muduo/net/InetAddress.h> #include <muduo/net/SocketsOps.h> #include <stdio.h> using namespace muduo; using namespace muduo::net; void newConnection(int sockfd, const InetAddress& peerAddr) { printf("newConnection(): accepted a new connection from %s\n", peerAddr.toIpPort().c_str()); ::write(sockfd, "How are you?\n", 13); sockets::close(sockfd); } int main() { printf("main(): pid = %d\n", getpid()); InetAddress listenAddr(8888);//端口8888 EventLoop loop; Acceptor acceptor(&loop, listenAddr); acceptor.setNewConnectionCallback(newConnection);//设置回调函数 acceptor.listen(); loop.loop(); }
/// Acceptor of incoming TCP connections. /// class Acceptor : noncopyable { public: typedef std::function<void (int sockfd, const InetAddress&)> NewConnectionCallback; Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); ~Acceptor(); void setNewConnectionCallback(const NewConnectionCallback& cb) { newConnectionCallback_ = cb; } void listen(); bool listening() const { return listening_; } // Deprecated, use the correct spelling one above. // Leave the wrong spelling here in case one needs to grep it for error messages. // bool listenning() const { return listening(); } private: void handleRead(); //通道Channel的回调函数 EventLoop* loop_; //所在EventLoop Socket acceptSocket_; //socket类 Channel acceptChannel_; //通道 NewConnectionCallback newConnectionCallback_; //在handleRead()中调用 bool listening_; //是否在listen int idleFd_; };
Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) : loop_(loop), acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), acceptChannel_(loop, acceptSocket_.fd()), listening_(false), idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) { assert(idleFd_ >= 0); acceptSocket_.setReuseAddr(true); acceptSocket_.setReusePort(reuseport); acceptSocket_.bindAddress(listenAddr); //绑定地址 acceptChannel_.setReadCallback( std::bind(&Acceptor::handleRead, this)); //通道回调函数 }
void Acceptor::handleRead() { loop_->assertInLoopThread(); InetAddress peerAddr; //FIXME loop until no more int connfd = acceptSocket_.accept(&peerAddr); //accept 新连接 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 libev. if (errno == EMFILE) { ::close(idleFd_); idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); ::close(idleFd_); idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); } } }
//Accepter.cc void Acceptor::listen() { loop_->assertInLoopThread(); listening_ = true; acceptSocket_.listen(); acceptChannel_.enableReading(); //注册到poller监听事件 } //Socket.cc void Socket::listen() { sockets::listenOrDie(sockfd_); } //SocketsOps.cc void sockets::listenOrDie(int sockfd) { int ret = ::listen(sockfd, SOMAXCONN); if (ret < 0) { LOG_SYSFATAL << "sockets::listenOrDie"; } }