Reputation: 5458
Consider the following code (Boost 1.76 / Asio 1.18.2):
#include <chrono>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
namespace asio = boost::asio;
int main() {
boost::system::error_code ec;
asio::io_service ios;
asio::ip::tcp::endpoint ep;
asio::ip::tcp::acceptor acc(ios);
acc.open(ep.protocol(), ec);
acc.bind(ep, ec);
acc.listen();
asio::ip::tcp::socket sock(ios);
acc.accept(sock);
std::this_thread::sleep_for(std::chrono::seconds(2));
auto str = std::string{"hello"};
sock.write_some(asio::buffer(str), ec);
std::cout << ec.message() << std::endl;
// further write_some calls
}
If I run this program and connect to it (e.g. running something like curl $(netstat -lp | grep 'main *$' | awk '{ print $4 }'
), then it outputs Success
. However, if I abort the connection (e.g. by giving SIGINT to curl) before the server sends any data, it still outputs Success
(the first time)! Subsequent write_some
calls give the error Broken pipe
.
Since TCP is supposed to guarantee delivery, I'm surprised that the program would output Success
even after the receiver has exited. Is there a way to check whether the data was delivered according to the TCP protocol? Some kind of flush function?
Upvotes: 0
Views: 196
Reputation: 36379
TCP will detect the error eventually, when write_some
returns the data has been accepted into the OS TCP stack it doesn't wait until the data has been delivered and acknowledged. When the OS detects an error (e.g. a connection reset, or a timeout waiting for an ACK) it has no way to communicate that error back through the sockets API so it holds on to the error and returns it via the next call to the sockets API. You can only be reasonably certain all your messages have been delivered on completion of a graceful shutdown of the socket.
Upvotes: 1