我正在嘗試使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