如何确定套接字何时接收EOF?(C++20的辅助程序)



考虑一个简单的echo服务器:

#include <boost/asio.hpp>
#include <boost/asio/experimental/as_tuple.hpp>
#include <iostream>
#include <vector>
using boost::asio::awaitable;
using boost::asio::buffer;
using boost::asio::co_spawn;
using boost::asio::io_context;
using boost::asio::detached;
namespace ip = boost::asio::ip;
using boost::asio::use_awaitable;
// echo server
awaitable<void> serve_coroutine(ip::tcp::socket s) {
std::vector<unsigned char> data_buf;
data_buf.resize(4096);
for (;;) {
auto n = co_await s.async_read_some(buffer(data_buf, data_buf.size()),
use_awaitable);
auto ep = s.remote_endpoint();
std::cout << "R from " << ep.address().to_string()
<< " " << ep.port() << " L=" << n << std::endl;
while (n) {
size_t written = co_await s.async_write_some(buffer(data_buf, n), use_awaitable);
n -= written;
}
}
}
awaitable<void> listen_coroutine(ip::tcp::acceptor& acceptor) {
for (;;) {
auto [e, client] = co_await acceptor.async_accept(
boost::asio::experimental::as_tuple(use_awaitable));
if (!e) {
auto ex = client.get_executor();
// create working coroutine for data-transmission
co_spawn(ex, serve_coroutine(std::move(client)), detached);
} else {
std::cerr << "accept failed: " << e.message() << std::endl;
}
}
}
int main(int argc, char** argv) {
if (argc < 3) {
std::cout << "Usage: " << argv[0]
<< " <bind_address> <bind_port>" << std::endl;
return 1;
}
try {
io_context ctx;
// bind address
ip::tcp::endpoint listen_endpoint{ip::make_address(argv[1]),
static_cast<ip::port_type>(std::stoi(argv[2]))};
// create acceptor
ip::tcp::acceptor acceptor{ctx, listen_endpoint};
// add coroutine to execution queue
co_spawn(ctx, listen_coroutine(acceptor), detached);
// start executing coroutines
ctx.run();
} catch (boost::system::system_error& e) {
std::cerr << "boost system error: " << e.what() << std::endl;
} catch (std::exception& e) {
std::cerr << "E: " << e.what() << std::endl;
}
return 0;
}

(使用g++ -std=c++20clang++ -stdlib=libc++ -fcoroutines-ts构建(

当远程对等方关闭连接时,co_await async_read_some从不返回

boost io_service似乎只是在关闭连接时破坏了一切

如果我在serve_coroutine中插入一个对象并跟踪它的构造函数和析构函数,我可能会发现它在关闭连接时被析构函数

那么,处理连接关闭事件的正确方法是什么?如果你正在开发一款游戏,你需要清除玩家的数据,并在你确定他的连接关闭时告诉每个人他已经离线

您可以捕获异常:

for (;;) {
try {
auto n = co_await s.async_read_some(
buffer(data_buf, data_buf.size()), use_awaitable);
auto ep = s.remote_endpoint();
std::cout << "R from " << ep.address().to_string() << " "
<< ep.port() << " L=" << n << std::endl;
while (n) {
size_t written = co_await s.async_write_some(
buffer(data_buf, n), use_awaitable);
n -= written;
}
} catch (std::exception& e) {
std::cerr << "boost system error: " << e.what() << std::endl;
}
}

哪个将打印

boost system error: End of file [asio.misc:2]

或者,您可以使用另一种方法来接收error_code。你可以在你的清单中看到一个例子:

auto [e, client] = co_await acceptor.async_accept(
boost::asio::experimental::as_tuple(use_awaitable));

因此,例如:

for (;;) {
auto [ec, n] = co_await s.async_read_some(
buffer(data_buf, data_buf.size()),
boost::asio::experimental::as_tuple(use_awaitable));
auto ep = s.remote_endpoint();
std::cout << "R from " << ep.address().to_string() << " " << ep.port()
<< " L=" << n << " (" << ec.message() << ")" << std::endl;
if (!ec)
break;
while (n) {
size_t written =
co_await s.async_write_some(buffer(data_buf, n), use_awaitable);
n -= written;
}
}

将显示以下内容:

R from 127.0.0.1 51586 L=4 (Success)
R from 127.0.0.1 51586 L=1 (Success)
R from 127.0.0.1 51586 L=1 (Success)
R from 127.0.0.1 51586 L=1 (Success)
R from 127.0.0.1 51586 L=0 (End of file)
R from 127.0.0.1 51590 L=1 (Success)
R from 127.0.0.1 51590 L=1 (Success)
R from 127.0.0.1 51590 L=0 (End of file)

相关内容

最新更新