问题描述:
accept处理连接时,若出现 EMFILE 错误不进行处理,则内核间隔性尝试连接,导致整个网络设计程序崩溃,因此需要处理这不当的请求。对于用户而言,处理该请求的关键就是文件描述符,然而没有请求成功就不存在相应的文件描述符,这是一个麻烦的问题,下面借由muduo库(方法来源于libev)简单说明一下解决方案。
方案:
事先创建一个指向空文件( /dev/null )的 idlefd 文件描述符,当出现 EMFILE错误时,将该文件描述符关闭,并重新接收请求;此时idlefd就是连接请求的 fd ,该fd是不当请求,将其关闭::close(fd),然后重置idlefd文件描述符指向,以备后续使用。
程序
(摘自陈硕的高并发muduo网络库,Acceptor封装类)
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);
}
}
}