【发布时间】:2020-03-02 19:30:42
【问题描述】:
我注意到在 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() 行挂起,因为在几次 Broken pipe 错误后未调用 async_write 完成处理程序。我希望任何 async_write 操作都应该导致处理程序调用,而不管 OSX 版本中的套接字状态如何。
是linux版本的bug吗?
Asio 版本:1.14.0(独立)
【问题讨论】:
-
我没有找到解决方案。最后我只是在写处理程序中处理错误代码并关闭套接字并在出现错误时停止发送数据。
标签: c++ sockets networking boost-asio asio