Я заметил, что в OSX функция asio :: async_write всегда вызывает обработчик обратного вызова. Но на linux (Ubuntu 18.04) после того, как операция async_write завершается с ошибкой 3 раза (сброс соединения по одноранговому или сломанному каналу), обратный вызов обработчика больше не вызывается после следующего вызова async_write.
Пожалуйста, посмотрите на Пример кода:
asio::io_service ioService;
asio::ip::tcp::resolver resolver(ioService);
// ---- Initialize server -----
auto acceptor = make_unique<asio::ip::tcp::acceptor>(ioService,
resolver.resolve(asio::ip::tcp::resolver::query(asio::ip::tcp::v4(), "localhost", "12345"))->endpoint());;
asio::ip::tcp::socket serverSocket(ioService);
std::promise<void> connectedPromise;
std::promise<void> disconnectedPromise;
std::vector<uint8_t> readBuffer(1);
acceptor->async_accept(serverSocket, [&](asio::error_code errorCode) {
std::cout << "Socket accepted!" << std::endl;
connectedPromise.set_value();
serverSocket.async_read_some(asio::buffer(readBuffer), [&](asio::error_code errorCode, std::size_t length) {
if (errorCode) {
std::cout << "Read error: " << errorCode.message() << std::endl;
disconnectedPromise.set_value();
}
});
});
// ----- Initialize client --------
asio::ip::tcp::socket clientSocket(ioService);
asio::connect(clientSocket, resolver.resolve({asio::ip::tcp::v4(), "localhost", "12345"}));
// ----- Start io service loop
std::thread mainLoop([&]() {
ioService.run();
});
connectedPromise.get_future().get(); // Wait until connected
// ----- Perform 10 async_write operations with 100 ms delay --------
std::promise<void> done;
std::atomic<int> writesCount{0};
std::vector<uint8_t> writeBuffer(1);
std::function<void (const asio::error_code&, std::size_t)> writeHandler = [&](const asio::error_code& errorCode, std::size_t) -> void {
if (errorCode) {
std::cout << errorCode.message() << std::endl;
}
if (++writesCount < 10) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
asio::async_write(serverSocket, asio::buffer(writeBuffer), writeHandler);
} else {
done.set_value();
}
};
asio::async_write(serverSocket, asio::buffer(writeBuffer), writeHandler);
clientSocket.close(); // Perform disconnect from client side
disconnectedPromise.get_future().get(); // Wait until disconnected
std::cout << "Waiting for all operations complete" << std::endl;
done.get_future().get(); // Wait until all 10 async_write operations complete
std::cout << "All operations complete" << std::endl;
ioService.stop();
mainLoop.join();
Вывод в OSX:
Socket accepted!
Broken pipe
Read error: Connection reset by peer
Broken pipe
Waiting for all operations complete
Broken pipe
Broken pipe
Broken pipe
Broken pipe
Broken pipe
Broken pipe
Broken pipe
All operations complete
Вывод в Ubuntu 18.04:
Socket accepted!
Read error: End of file
Connection reset by peer
Waiting for all operations complete
Broken pipe
Broken pipe
Linux версия зависает на строке done.get_future().get()
, потому что Обработчик завершения async_write не вызывается после нескольких ошибок сломанной трубы. Я ожидаю, что любая операция async_write должна привести к вызову обработчика независимо от состояния сокета, как в версии OSX. Это ошибка в linux версии?
Версия Asio: 1.14.0 (автономная версия)