我正在尝试使asio和SSL的朋友。 一切进展顺利,但有一件事情造成不便:如何在 检测到对端关闭连接,并且当对端在发送数据时只是短暂休息时,将其与 区分开来,几秒后继续 ?boost :: asio和async SSL流:如何检测数据结束/连接关闭?
- 升压1.48
- OpenSSL的1.0.0e
- 使用VS10
- 上W7 64工作编译为32位代码。
我的困惑来自这样一个事实,即对于 普通套接字和SSL流,asio行为不同。 如果我使用tcp :: socket - 当对等关闭连接时收到EOF错误。 但是对于boost :: asio :: ssl :: stream - 它不是 。相反,async_read_some返回0作为字节传输, ,如果我试图继续读取SSL流 - 返回short_error (http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/streams.html)。
所以,问题是:它是预期的行为,还是我错误配置任何东西?
客户端的代码片段:
class client
{
public:
// bla-bla-bla-bla-bla ....
//
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(reply_, max_length),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Write failed: " << error.message() << "\n";
}
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
std::cout << "Bytes transfered: " << bytes_transferred << "\n";
if (!error)
{
std::cout << "Reply: ";
std::cout.write(reply_, bytes_transferred);
std::cout << "\n";
std::cout << "Reading...\n";
socket_.async_read_some(boost::asio::buffer(reply_, max_length),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else if (0 != bytes_transferred)
{
std::cout << "Read failed: " << error.message() << ":"
<< error.value() << "\n";
}
}
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
boost::asio::streambuf request_;
char reply_[max_length];
};
如果我们去除如果(!0 = bytes_transferred),我们会得到 “短读” :(
如果我们将使用代码为爱,输出将是这样的:
请求是:
GET/HTTP/1.0
的Cookie:那抹-NAMA =瓦拉-VALA
字节转移:1024
答复:HTTP/1.0 200 OK 内容类型:文本/ HTML
..... BLA -bla-BLA ....
阅读... 字节转移:1024
.....喇嘛喇嘛喇嘛.... .....喇嘛喇嘛,喇嘛....
个阅读... 字节转移:482
.....喇嘛喇嘛喇嘛....
读...
字节转移:0
与此同时,如果不是async_read_some我们写代码, 普通插座将EOF返回的内容:
boost::asio::async_read(socket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&client::handle_read_content, this,
boost::asio::placeholders::error));
然后SSL插座,我们将得到0作为字节传输,然后short_read。
我知道在没有办法检测断开连接的情况下,如果对方(例如 示例)刚刚从网络中拔出。 但是如何检测明确的干净的同行脱节当 对端只是不发送数据一段时间,但可能会做到这一点 稍后?
或者,可能是我不明白的东西?
WBR, 安德烈
一些addentum: SSL/TLS有符号告知对方关于关闭连接。 它close_notify警报。底层TCP套接字也可以关闭。因此,基本上,我的问题是:为什么在相同的条件下(TCP套接字已清楚地关闭),我在tcp :: socket的情况下收到EOF,并且没有收到任何用于boost :: asio :: ssl的东西: :流。
它是错误还是asio功能?
又一个原因: 由于某些原因,如果SSL收到close_notify或底层TCP套接字已关闭,asio不会给我一个EOF。
是的,我可以通过超时检测死连接。 但是,如何检测正确关闭的SSL连接?通过接收short_read?
SSL/TLS有通知通知对方关闭连接。 它close_notify警报。同时底层的TCP套接字也被关闭。因此,基本上,我的问题是:为什么在相同的条件下(TCP套接字已清楚地关闭),我在tcp :: socket的情况下收到EOF,并且没有收到任何boost :: asio :: ssl :: stream 。 它是错误还是功能? – Amdei
当然,'close_notify'用于干净的关闭,这不会帮助您检测到坏的关闭。我不太了解'boost :: asio :: ssl :: stream',但我的猜测是你正在进行异步操作,SSL/TLS的关闭会导致异步操作的问题(请参阅“正确关闭SSLSocket”链接以上)。这可能会解释一个稍微不同的行为。无论哪种方式,这并不重要。这不会是一个需要修复的bug,因为它不是找到什么时候停止从流/套接字读取的正确方法。 – Bruno
顺便说一句,我不确定你的意思是“* close_notify alert。还有底层的TCP套接字被关闭。*”,但是TLS关闭警告并不意味着底层的TCP套接字必须关闭。 – Bruno