ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

muduo源码分析之Acceptor

2021-05-22 12:04:34  阅读:227  来源: 互联网

标签:muduo Socket void 源码 net loop Acceptor


相关文件

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源码分析

Acceptor类

/// 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";
  }
}

标签:muduo,Socket,void,源码,net,loop,Acceptor
来源: https://www.cnblogs.com/Lj-ming/p/14798458.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有