如何使用boost::asio从网络中断中恢复

How to recover from network interruption using boost::asio

本文关键字:中断 恢复 网络 asio 何使用 boost      更新时间:2023-10-16

我正在编写一个接受来自设备的数据并处理它的服务器。除非网络中断(即,如果我拔下以太网电缆,然后重新连接(,否则一切正常。我正在使用 read_until((,因为设备使用的协议以特定的字节序列终止数据包。当数据流中断时,read_until(( 会按预期进行阻塞。但是,当流再次启动时,它仍然处于阻塞状态。如果我查看Wireshark的数据流,设备继续传输,每个数据包都被网络堆栈确认。但如果我看bytes_readable它总是 0。如何检测中断以及如何重新建立与数据流的连接?下面是一个代码片段,提前感谢您提供的任何帮助。[放轻松,这是我的第一个堆栈溢出问题......是的,我确实试图寻找答案。

using boost::asio::ip::tcp;
boost::asio::io_service IOservice;
tcp::acceptor acceptor(IOservice, tcp::endpoint(tcp::v4(), listenPort));
tcp::socket socket(IOservice);
acceptor.accept(socket);
for (;;)
{
len = boost::asio::read_until(socket, sbuf, end);
// Process sbuf
// etc.
}

请记住,客户端会启动连接,因此您唯一需要做的就是重新创建套接字并重新开始接受。我将保留您的代码片段的格式,但我希望您的真实代码已正确封装。

using SocketType = boost::asio::ip::tcp::socket;
std::unique_ptr<SocketType> CreateSocketAndAccept(
boost::asio::io_service& io_service,
boost::asio::ip::tcp::acceptor& acceptor) {
auto socket = std::make_unique<boost::asio::ip::tcp::socket>(io_service);
boost::system::error_code ec;
acceptor.accept(*socket.get(), ec);
if (ec) {
//TODO: Add handler.
}
return socket;
}
...
auto socket = CreateSocketAndAccept(IOservice, acceptor);
for (;;) {
boost::system::error_code ec;
auto len = boost::asio::read_until(*socket.get(), sbuf, end, ec);
if (ec)  // you could be more picky here of course,
// e.g. check against connection_reset, connection_aborted
socket = CreateSocketAndAccept(IOservice, acceptor);
...
}

脚注:不言而喻,socket需要保持在范围内。

编辑:基于下面的评论。

侦听套接字本身不知道客户端是静音还是被切断。所有操作,尤其是同步操作,都应对完成施加时间限制。考虑设置SO_RCVTIMEOSO_KEEPALIVE(每个套接字或系统范围,有关详细信息 如何正确使用SO_KEEPALIVE选项来检测另一端的客户端是否关闭?

另一种选择是异步并实现一个成熟的"共享"套接字服务器(BOOST 示例页面是一个很好的开始(。

无论哪种方式,您都可能遇到数据一致性问题并被迫处理它,例如,当客户端检测到连接中断时,它会重新发送数据。(或使用更高级别协议更复杂的协议(

如果你想保持同步,我看到的处理方式是在检测到中断时销毁套接字。阻止调用应引发可以捕获的异常,然后再次开始接受连接。

for (;;)
{
try {
len = boost::asio::read_until(socket, sbuf, end);
// Process sbuf
// etc.
}
catch (const boost::system::system_error& e) {
// clean up. Start accepting new connections.
}
}

正如 Tom 在他的回答中提到的,不活动和不优雅的断开连接之间没有区别,因此您需要一个外部机制来检测这一点。

如果您期望连续数据传输,也许服务器端的每个连接超时就足够了。一个简单的ping也可以工作。接受连接后,每 X 秒 ping 一次客户端,如果他不回答,则宣布连接失效。