无法检测C ++同步boost :: asio :: ip :: tcp :: socket连接被关闭 [英] Unable to detect C++ synchronous boost::asio::ip::tcp::socket connection being closed
问题描述
我使用 boost :: asio
创建一个同步TCP套接字连接到在同一台计算机上运行的node.js TCP服务器应用程序。我使用Embarcadero RAD studio XE4在Windows上构建64位应用程序,使用Embarcadero集成boost版本1.50。
I am using boost::asio
to make a synchronous TCP socket connection to a node.js TCP server application that runs on the same computer. I am using Embarcadero RAD studio XE4 on Windows building 64 bit application that uses the Embarcadero integrated boost version 1.50.
除了node.js TCP服务器关闭。当这种情况发生时,我的C ++客户端应用程序不会检测到断开连接,当我从套接字读取。然而,它在我写入套接字时检测到断开连接。
Things work fine except when the node.js TCP server shuts down. When this occurs my C++ client application does not detect the disconnection when I read from the socket. However, it does detect the disconnection when I write to the socket.
我当前的代码是在尝试了解boost文档和SO的各种答案后写的。代码的读取部分如下(我已经省略了紧凑性错误代码的检查)
My current code was written after trying to make sense of the boost documentation and a variety of answers here on SO. The reading portion of the code is as follows (I have omitted the checking of the error code for compactness)
boost::system::error_code ec;
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket s(io_service);
boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"),m_port);
ec = s.connect(ep,ec);
std::size_t bytes_available = s.available(ec);
std::vector<unsigned char> data(bytes_available,0);
size_t read_len = boost::asio::read(s, boost::asio::buffer(data),boost::asio::transfer_at_least(bytes_available),ec);
if ((boost::asio::error::eof == ec) || (boost::asio::error::connection_reset == ec))
{
// disconnection
break;
}
这不是一个伟大的系统,因为它在自己的线程中运行循环和轮询数据,直到程序关闭。通常我不会在套接字上执行 read()
,但没有数据,但在这种情况下,因为所有的文档导致我相信套接字断开连接仅在对套接字执行读取或写入时才会检测到。问题是,当node.js应用程序关闭时,上述代码根本不会检测到断开连接。如果我写我检测它(代码的写部分使用相同的boost :: asio :: error`错误作为读检测),但不是在阅读时。
This is not a great system as it is running in its own thread inside a loop and polling for data constantly until the program is shutdown. Normally I would not perform a read()
on a socket when there is no data there but I do it in this case since all documentation leads me to believe that the socket disconnection is detected only when performing a read or write to the socket. The problem is that the above code is simply never detecting the disconnection when the node.js application shuts down. If I am writing I detect it (the write part of the code is using the same boost::asio::error` errors as the read for detection) but not when reading.
显然,我不能执行读取字节量大于可用或我的线程将阻塞,我将无法执行写入以后在我的线程循环。
Obviously I cannot perform a read for byte amounts larger than that are available or my thread will block and I will be unable to perform writes later on in my thread loop.
我缺少另一个特定的提升错误代码来检测错误条件?或者它是一个问题,特别是零长度读取。如果是这样,我还有其他选择吗?
Am I missing another specific boost error code to detect the error condition? Or is it a problem specifically with the zero length read. If that is the case are there any other options available to me?
目前我得到node.js服务器写出一个特定的消息,当它到套接字它关闭,我检测,然后关闭客户端我自己。但是,这是一个黑客,我希望一个干净的方式来检测断开,如果可能的话。
Currently I am getting the node.js server to write out a specific message when it to the socket when it shuts down which I am detecting and then closing the client end myself. However, this is a bit of a hack and I would prefer a clean way to detect the disconnect if possible.
推荐答案
,Boost.Asio的 read()
函数返回:
In general, Boost.Asio's read()
functions return when either:
- 缓冲区
- 已满足完整条件。
- 发生错误。
未指定检查这些条件的顺序。然而,上次我看看实现,Boost.Asio处理操作,在尝试从套接字读取之前读取流上的零字节作为无操作。
It is unspecified as to the order in which these conditions are checked. However, last time I looked at the implementation, Boost.Asio treated operations that read zero bytes on a stream as a no-op prior to attempting reading from the socket. Hence, an end of file error will not be observed, because the 0 size buffer is considered full.
使用异步操作可能会提供更好的结果和可扩展性,检测到以非阻塞方式断开仍然可以用同步操作来完成。默认情况下,同步操作是阻塞的,但这种行为可以通过
socket :: non_blocking()
功能。文档说明:
While using asynchronous operations will likely provide better results and scalability, detecting a disconnect in a non-blocking manner can still be accomplished with synchronous operations. By default, the synchronous operations are blocking, but this behavior can be controlled via the
socket::non_blocking()
function. The documentation states:
如果
true
,套接字的同步操作将失败, code> boost :: asio :: error :: would_block ,如果他们无法立即执行请求的操作。如果false
,同步操作将阻塞,直到完成。
If
true
, the socket's synchronous operations will fail withboost::asio::error::would_block
if they are unable to perform the requested operation immediately. Iffalse
, synchronous operations will block until complete.
同步操作设置为不阻塞,并且读取操作尝试读取至少1个字节,则可以以非阻塞方式观察到断开连接。
Therefore, if the synchronous operations are set to not block and the read operation attempts to read a minimum of 1 byte, then a disconnect can be observed in a non-blocking manner.
这是一个完整的例子演示一个非阻塞同步 read()
操作检测断开连接。为了节流打印消息,我选择在操作被阻止时执行睡眠(即有连接,但没有数据可供读取)。
Here is a complete example demonstrating a non-blocking synchronous read()
operation that detects a disconnect. In order to throttle the print messages, I have opted to perform a sleep when the operation would have blocked (i.e. has a connection but no data is available to read).
#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
int main(int argc, char* argv[])
{
if (argc != 2)
{
std::cerr << "Usage: <port>\n";
return 1;
}
// Create socket and connet to local port.
namespace ip = boost::asio::ip;
boost::asio::io_service io_service;
ip::tcp::socket socket(io_service);
socket.connect(ip::tcp::endpoint(
ip::address::from_string("127.0.0.1"), std::atoi(argv[1])));
// By setting the socket to non-blocking, synchronous operations will
// fail with boost::asio::error::would_block if they cannot immediately
// perform the requested operation.
socket.non_blocking(true);
// Synchronously read data.
std::vector<char> data;
boost::system::error_code ec;
for (;;)
{
// Resize the buffer based on the amount of bytes available to be read.
// Guarantee that the buffer is at least 1 byte, as Boost.Asio treats
// zero byte read operations as no-ops.
data.resize(std::max<std::size_t>(1, socket.available(ec)));
// Read all available data.
std::size_t bytes_transferred =
boost::asio::read(socket, boost::asio::buffer(data), ec);
// If no data is available, then continue to next iteration.
if (bytes_transferred == 0 && ec == boost::asio::error::would_block)
{
std::cout << "no data available" << std::endl;
boost::this_thread::sleep_for(boost::chrono::seconds(3));
continue;
}
std::cout << "Read: " << bytes_transferred << " -- ";
if (bytes_transferred)
{
std::cout.write(&data[0], bytes_transferred);
std::cout << " -- ";
}
std::cout << ec.message() << std::endl;
// On error, such as a disconnect, exit the loop.
if (ec && ec != boost::asio::error::would_block)
{
break;
}
}
}
将示例程序连接到写入test,更多测试的服务器,然后关闭连接:
The following output was produced by connecting the example program to a server that wrote "test", "more testing", then closed the connection:
no data available
Read: 4 -- test -- Success
no data available
Read: 12 -- more testing -- Success
Read: 0 -- End of file
这篇关于无法检测C ++同步boost :: asio :: ip :: tcp :: socket连接被关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!