【发布时间】:2020-05-22 14:17:43
【问题描述】:
我目前有一个非常奇怪的问题。有时我的 ::acceptor(使用 async_accept)不接受套接字(没有调用 async_accept 中指定的接受函数)但连接器在连接函数上返回 true(boost::asio:: em> 类)。有时一切正常,但有时我没有接受器套接字....我真的不知道为什么了。我用不同的listen_ports在Win10 64bit下测试了所有东西。
我的服务器结构如下:
io_service:
_io_thread = std::make_unique<std::thread>([this]() {
while (1)
{
try
{
_io_service->run();
break;
}
catch (const boost::exception& e)
{
spdlog::error("IO_SERVICE_EXCEPTION: ", boost::diagnostic_information(e));
}
}
});
接受者:
void Server::initialize(uint16_t listen_port)
{
// at this point the io_thread is running already
auto endpoint = ip::tcp::endpoint(ip::tcp::v4(), listen_port);
_acceptor = std::make_unique<boost::asio::ip::tcp::acceptor>(*_io_service, endpoint.protocol());
_acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(false));
_acceptor->bind(endpoint);
_acceptor->listen();
_listen_port = listen_port;
__accept();
}
__accept():
void Server::__accept()
{
// create socket for next connection
_acceptor_socket = std::make_unique<ip::tcp::socket>(*_io_service);
_acceptor->async_accept(*_acceptor_socket, [this](const boost::system::error_code& err)
{
spdlog::info("Accept new socket..."); // this sometimes doesn't get called :(
if (err.failed())
{
// acceptor closed
if (err == boost::asio::error::operation_aborted)
{
spdlog::info("network server stopped accepting sockets");
return;
}
// unknown error
spdlog::error("network server accepting socket failed {} message {} num {}", err.failed(), err.message(), err.value());
// accept next connection
__accept();
return;
}
// accept new socket
_new_connections_mutex.lock();
auto con = __create_new_connection();
con->initialize(++_connection_id_counter, std::move(_acceptor_socket));
con->set_handler(_input_handler);
con->goto_phase(_initial_phase);
spdlog::info("new connection from {} with id {}", con->get_host_name(), con->get_unique_id());
_new_connections[con->get_unique_id()] = std::move(con);
_new_connections_mutex.unlock();
// wait for next connection
__accept();
}
);
}
我的客户端连接器很简单:
auto socket = std::make_unique<boost::asio::ip::tcp::socket>(*_io_service);
spdlog::info("try to connect to {}:{}", endpoint.address().to_string(), endpoint.port());
try
{
socket->connect(endpoint);
}
catch (const boost::system::system_error & e)
{
spdlog::error("cannot connect to {}:{}", endpoint.address().to_string(), endpoint.port());
return false;
}
// this succeeds everytime...
[...]
所以...不应该每次连接器套接字成功连接接受器套接字时也创建吗?我希望有人知道这里出了什么问题:/
【问题讨论】:
-
等等,你为什么把reuse_address设置为false?我不完全确定它实际上做了什么(它总是一个隐藏的谜团),但它可能会导致它在短时间内无法从同一地址重新打开套接字。
-
以
__开头的标识符在所有范围中都保留;使用它们在技术上是 UB stackoverflow.com/questions/228783/… -
代码中有几条日志语句。当您遇到有问题的行为时,您会看到哪些?
-
如果互斥锁
.lock()和.unlock()之间发生异常,您将出现软锁或死锁。很少需要使用这些,而是使用异常安全的std::lock_guard、std::unique_lock或std::shared_lock -
@sehe:到目前为止,我将 __ 用于私有和受保护的成员函数,_ 用于成员变量。你有什么建议吗?我阅读了 glibc 页面,是的 __ 是为全局 C 函数保留的...... std::lock_guard 的要点实际上是一个好点。我会改变的。连接器套接字(“尝试连接到...”)已成功创建(实际上在那之后是另一个验证该内容的日志)但日志“接受新套接字...”有时会出现,有时不会出现(如果它没有'在它可以接受套接字之前我必须重新启动服务器......)
标签: c++ sockets network-programming boost-asio