限制并发连接数

  1. 不希望服务程序超载
  2. file descriptor 是稀缺资源, fd 耗尽是一件麻烦事

若accpet(2) 返回 EMFILE 该如何应对?这意味着本进程的文件描述符已经到达上限,无法为新连接创建 socket 文件描述符。但是,既然没有 socket 文件描述符来表示这个连接,我们就无法 close(2)它。程序继续运行,回到epoll_wait处 。这时 epoll_wait 会马上返回,因为新连接还在等待处理,listening fd 还是可读的。这样程序就陷入了 busy loop,CPU 占用率接近 100%,这既影响同一 eventloop 上的连接,也影响同一机器上的其他服务。

陈硕的 《linux多线程服务端编程》中提到了以下几种做法:

  1. 调高进程的文件描述符数目。治标不治本
  2. 死等。鸵鸟算法
  3. 退出程序。不可取
  4. 关闭 listenning fd. 那么什么时候再打开呢?
  5. 改用 edge trigger。如果漏掉一次 accept(2),程序再也不会接受新连接(这会出现客户端无响应的情况)
  6. 准备一个空闲的文件描述符。
    准备一个空闲的文件描述符。遇到这种情况,先关闭这个空闲文件,获得一个文件描述符地名额;再accept(2)拿到新socket 连接的描述符;随后立刻close(2)它,这样就优雅地断开了客户端连接;最后重新打开一个空闲文件,把"坑"占住,以备再次出现这种情况时使用
  7. 自己设置一个低一点的soft limit.

muduo网络库中使用的是,第6种,代码如下:

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 libev.
    if (errno == EMFILE)
    {
      // 描述符用尽
      ::close(idleFd_);
      idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);
      ::close(idleFd_);
      // 再次打开占位
      idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
    }
  }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东阳z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值