如何在接受器循环中从 ENFILE 中恢复
How to recover from ENFILE in acceptor loop
我写了一个测试来显示asio async_accept的问题我有一台服务器,可以永远打开与它的任何连接在接受许多连接(在我的例子中为 1017)之后,下一个连接失败,出现"打开的文件过多"错误。然后,对async_accept的任何调用都会立即调用处理程序
这是误会吗?
我使用 debian 7 amd64
生成文件
CXX=clang++ -O2
OBJ= main.o server.o
LIBS=-lboost_system -lboost_thread
all: server
server: $(OBJ)
$(CXX) -o server $(OBJ) $(LIBS)
main.o: main.cpp
$(CXX) -c main.cpp
server.o: server.hpp server.cpp
$(CXX) -c server.cpp
clean:
rm -f *.o *~
distclean: clean
rm -f server
服务器.hpp
#include <boost/asio.hpp>
class server
{
public:
server();
void run();
private:
void start_accept();
void handle_accept(const boost::system::error_code& e);
boost::asio::io_service ios;
boost::asio::ip::tcp::acceptor acceptor_;
std::vector<boost::asio::ip::tcp::socket*> sockets;
};
服务器.cpp
#include <boost/bind.hpp>
#include "server.hpp"
server::server(): acceptor_(ios)
{
boost::asio::ip::tcp::resolver resolver(ios);
boost::asio::ip::tcp::resolver::query query("0.0.0.0", "5050");
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor_.open(endpoint.protocol());
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
acceptor_.bind(endpoint);
acceptor_.listen();
start_accept();
}
void server::run()
{
ios.run();
}
void server::start_accept()
{
boost::asio::ip::tcp::socket *s=new boost::asio::ip::tcp::socket(ios);
sockets.push_back(s);
acceptor_.async_accept(*s,
boost::bind(&server::handle_accept, this,
boost::asio::placeholders::error));
}
void server::handle_accept(const boost::system::error_code& e)
{
if(e)
{
std::cerr<<"e.message() = "<<e.message()<<std::endl;
boost::asio::ip::tcp::socket *s=sockets.back();
s->close();
delete s;
sockets.pop_back();
}
static int i=1;
std::cerr<<"i = "<<i++<<std::endl;
start_accept();
}
主.cpp
#include "server.hpp"
int main()
{
server s;
s.run();
return 0;
}
我的测试是
for x in `seq $1`;do nc 127.0.0.1 5050 & done
在server::handle_accept
结束时,即使套接字出错,您也会将异步接受提交回 IO 服务队列。
我不确定这是您想要的,但我可以通过在接受失败时重新启动侦听器来使其"工作"(恢复)。(请注意,如果在多个线程上运行服务,这将需要一些同步)。
住在科里鲁
#include <boost/asio.hpp>
class server
{
public:
server();
void run();
private:
bool start_listen();
void start_accept();
void handle_accept(boost::system::error_code e);
boost::asio::io_service ios;
boost::asio::ip::tcp::acceptor acceptor_;
std::vector<boost::asio::ip::tcp::socket*> sockets;
};
#include <boost/bind.hpp>
server::server(): acceptor_(ios)
{
start_listen();
start_accept();
}
void server::run()
{
ios.run();
}
bool server::start_listen()
{
boost::system::error_code e;
boost::asio::ip::tcp::endpoint endpoint { {}, 5050 };
acceptor_.open(endpoint.protocol());
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
acceptor_.bind(endpoint, e);
if (e)
return false;
acceptor_.listen();
return true;
}
void server::start_accept()
{
boost::asio::ip::tcp::socket *s=new boost::asio::ip::tcp::socket(ios);
sockets.push_back(s);
acceptor_.async_accept(*s, boost::bind(&server::handle_accept, this, boost::asio::placeholders::error));
}
#include <iostream>
void server::handle_accept(boost::system::error_code e)
{
if(e)
{
std::cerr<<"e.message() = "<<e.message()<<std::endl;
boost::asio::ip::tcp::socket *s=sockets.back();
s->close();
delete s;
sockets.pop_back();
acceptor_.close();
if (!start_listen())
return;
}
static int i=1;
std::cerr<<"i = "<<i++<<std::endl;
start_accept();
}
int main()
{
server s;
s.run();
}
当您以这种方式打开套接字时
boost::asio::ip::tcp::socket *s=new boost::asio::ip::tcp::socket(ios);
套接字没有打开,只是创建了一个对象。当您尝试接受它时,您达到了打开文件描述符限制,因此您会收到"打开文件太多"错误。然后,您只需将其从vector中删除,并创建另一个无法在接受中打开的套接字。我认为这就是错误的原因。
更新:顺便说一下,这个函数
void server::start_accept()
{
boost::asio::ip::tcp::socket *s=new boost::asio::ip::tcp::socket(ios);
sockets.push_back(s);
acceptor_.async_accept(*s,
boost::bind(&server::handle_accept, this,
boost::asio::placeholders::error));
}
似乎可能存在内存泄漏,如果在方法中生成异常push_back
,s
将丢失。
更新:如果您以这种方式重写handle_accept,则 inifinte 循环是固定的:
void server::handle_accept(const boost::system::error_code& e)
{
if(e)
{
auto size = 2;
for (int i = 0; i < size; ++i) {
std::cerr<<"e.message() = "<<e.message()<<std::endl;
boost::asio::ip::tcp::socket *s=sockets.back();
s->close();
delete s;
sockets.pop_back();
}
}
static int i=1;
std::cerr<<"i = "<<i++<<std::endl;
start_accept();
}
相关文章:
- 用C++将哈希表写入文件并从文件中恢复
- Opencv 恢复到比我设置的更高的分辨率
- 变量在使用赋值语句赋值后恢复为以前的值
- 在信号处理程序中捕获C++未处理的异常并恢复应用程序
- 删除所有字符串后如何恢复 QStringList?
- 当对套接字 send() 的同步调用由于连接另一端丢失而被阻止时,如何恢复?
- 如何仅使用一次固定<<设置精度(2)?或者至少恢复到默认行为?
- "co_yield"是否可以在恢复协程时从调用方返回值?
- OpenSSL C API:如何在程序exec()之后恢复TLS连接?
- 通过指针恢复对数组的引用.UB与否?
- 从不同进程中的另一个线程挂起/恢复线程或进程
- 如何在 XML 中正确存储原始字节数据并恢复它?
- ExtTextOut 文本的持续闪烁,在一段时间后,文本将恢复为默认字体
- 模板化类中运算符 + 重载的值的恢复
- C++ 线程创建/删除与线程停止/恢复
- ZMQ::send() 抛出异常并终止 QNX 进程.为什么以及如何从中恢复?
- Windows桌面程序保存您的计算机会话 - 基于程序崩溃时的恢复会话
- xSemaphoreTake 在调用 xSemaphoreGive 后不会恢复任务
- 将类型映射到整数值后,如何在给定整数值的情况下恢复类型?
- 如何在接受器循环中从 ENFILE 中恢复