gpt4 book ai didi

c++ - 如何从接受器循环中的 ENFILE 中恢复

转载 作者:行者123 更新时间:2023-11-30 05:48:30 25 4
gpt4 key购买 nike

我写了一个测试来显示 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

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

server.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();
}

main.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 服务队列,即使套接字有错误。

我不确定这是你想要的,但我可以通过在接受失败时重新启动监听器来使其“工作”(恢复)。 (请注意,如果您在多个线程上运行服务,这将需要一些同步)。

Live On Coliru

#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();
}

关于c++ - 如何从接受器循环中的 ENFILE 中恢复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28146721/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com