2011-12-11 32 views
15

Tôi đang cố gắng kết bạn với những người bạn asio và SSL. Mọi thứ diễn ra tốt đẹp, nhưng có một điều gây ra sự bất tiện: cách phát hiện xem kết nối ngang hàng và phân biệt nó với tình huống khi bạn chỉ mất một chút thời gian để gửi dữ liệu, để tiếp tục sau vài giây?boost :: asio và async SSL stream: làm thế nào để phát hiện kết thúc dữ liệu/kết nối gần?

  • tăng 1,48
  • OpenSSL 1.0.0e
  • Biên soạn mã 32-bit sử dụng VS10
  • Làm việc trên W7 x64.

Sự nhầm lẫn của tôi xuất phát từ thực tế, hành vi asio khác với ổ cắm thông thường và luồng SSL. Nếu tôi sử dụng tcp :: socket - tôi gặp lỗi EOF khi kết nối ngang hàng. Nhưng để tăng :: asio :: ssl :: stream - nó là không phải như vậy. Thay vào đó, async_read_some trả về 0 dưới dạng byte được chuyển, và nếu tôi cố gắng tiếp tục đọc từ luồng SSL - trả về short_error (http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/streams.html).

Vì vậy, các câu hỏi là: hành vi được mong đợi hay tôi định cấu hình sai?

Khách hàng đoạn mã:.

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]; 
}; 

Nếu chúng ta loại bỏ if (! = 0 bytes_transferred), chúng tôi sẽ nhận được "ngắn đọc" :(

Nếu chúng ta sẽ sử dụng mã như-ai , sản lượng sẽ là một cái gì đó như thế này:

Yêu cầu là:

GET/HTTP/1.0

Cookie: Nama-nama = Vala-vala

Bytes chuyển: 1024

Trả lời: HTTP/1.0 200 ok Content-type: text/html

..... bla -bla-bla ....

Reading ... Bytes chuyển: 1024

..... bla bla-bla-.... ..... bla bla-bla- ....

Reading ... Bytes chuyển: 482

..... bla bla-bla-....

Reading ...

Bytes chuyển: 0

Đồng thời, nếu thay vì async_read_some chúng ta viết mã, để làm gì ổ cắm thông thường sẽ trở lại EOF:

boost::asio::async_read(socket_, response_, 
    boost::asio::transfer_at_least(1), 
    boost::bind(&client::handle_read_content, this, 
    boost::asio::placeholders::error)); 

sau đó cho SSL socket chúng tôi sẽ nhận được 0 như byte chuyển giao, và sau đó short_read.

Tôi biết rằng không có cách nào để phát hiện ngắt kết nối trong trường hợp nếu ngang hàng, ví dụ , đã được rút phích cắm khỏi mạng. Nhưng làm thế nào để phát hiện xung đột rõ ràng trong sạch khi xảy ra tình huống khi ngang hàng không gửi dữ liệu trong một thời gian, nhưng có thể sẽ làm điều đó một chút sau?

Hoặc, có thể tôi không làm gì đó không ổn?

WBR, Andrey

Một số addentum: SSL/TLS có ký hiệu để thông báo cho bên kia về đóng kết nối. Nó đóng cảnh báo. Cũng có thể đóng socket TCP bên dưới. Vì vậy, về cơ bản, câu hỏi của tôi là: tại sao, trong điều kiện tương tự (TCP socket đã được đóng cửa rõ ràng) tôi nhận được EOF trong trường hợp tcp :: socket, và không nhận được bất cứ điều gì để tăng :: asio :: ssl: :suối.

Tính năng lỗi hoặc asio?

Một addentum khác: Vì một số lý do, asio không cung cấp cho tôi EOF nếu SSL nhận được close_notify cũng như TCP socket cơ bản đã bị đóng.

Có, tôi có thể phát hiện các kết nối đã chết vào thời gian chờ. Nhưng làm thế nào tôi có thể phát hiện các kết nối SSL được đóng đúng cách? Bằng cách nhận short_read?

Trả lời

5

Bạn có thể quan tâm đến các cuộc thảo luận:

Về cơ bản, thực tế là bạn có được một EOF đôi khi (thậm chí hầu hết thời gian) khi bên từ xa ngắt kết nối một ổ cắm TCP đơn giản chỉ là may mắn. Bạn không thể dựa vào nó trong trường hợp chung, vì nó không thể phân biệt giữa một ổ cắm không hoạt động và một ổ cắm đóng đột ngột mà không cần ghi vào nó.

Bạn cần xác định một số dấu phân cách, ở cấp giao thức ứng dụng, để biết khi nào nên dừng đọc. Trong HTTP, điều này được thực hiện thông qua dòng trống kết thúc tiêu đề (cho tiêu đề), tiêu đề Content-Length xác định chiều dài cơ thể hoặc các dấu phân tách chunked transfer encoding khi độ dài cơ thể không được biết trước.

+1

SSL/TLS có ký hiệu để thông báo cho bên kia về việc đóng kết nối. Nó đóng cảnh báo. Ngoài ra TCP socket đang được đóng. Vì vậy, về cơ bản, câu hỏi của tôi là: tại sao, trong điều kiện tương tự (TCP socket đã được đóng lại rõ ràng) Tôi nhận được EOF trong trường hợp tcp :: socket, và không nhận được bất cứ điều gì cho boost :: asio :: ssl :: stream . Lỗi hoặc tính năng? – Amdei

+0

Chắc chắn, 'close_notify' là dành cho đóng cửa sạch sẽ, điều đó sẽ không giúp bạn phát hiện ra những cái xấu. Tôi không biết nhiều về 'boost :: asio :: ssl :: stream', nhưng tôi đoán là bạn đang thực hiện các hoạt động không đồng bộ và việc đóng SSL/TLS sẽ gây ra vấn đề với các hoạt động không đồng bộ (xem" Đóng kết nối SSLSocket "đúng cách) ở trên). Nó có thể giải thích một hành vi hơi khác. Dù bằng cách nào, nó không thực sự quan trọng. Nó sẽ không phải là một lỗi mà cần sửa chữa, vì nó chỉ không phải là cách chính xác để tìm ra khi nào ngừng đọc từ một dòng/ổ cắm. – Bruno

+0

Nhân tiện, tôi không chắc chắn ý của bạn là gì "* Nó đóng cảnh báo. Ngoài ra ổ cắm TCP bên dưới bị đóng. *", Nhưng cảnh báo đóng cửa TLS không ngụ ý rằng ổ cắm TCP bên dưới phải được đóng lại. – Bruno

14

Lỗi SSL_R_SHORT_READ được mong đợi ở đây. Khi máy chủ khởi động tắt máy sạch sẽ với SSL_Shutdown điều này sẽ gửi cảnh báo tắt thông báo cho khách hàng. Việc triển khai Asio ánh xạ điều này thành lỗi SSL_R_SHORT_READ với danh mục error::get_ssl_category().Nó thực hiện điều này bằng cách phát hiện nếu peer đã khởi động tắt máy thông qua SSL_get_shutdown.

Điều này có thể được xem bằng cách kiểm tra tiêu đề asio/ssl/detail/impl/engine.ipp và cụ thể là chức năng engine::map_error_code(boost::system::error_code&).

Tôi tin rằng triển khai ssl được viết lại trong tăng 1.47, vì vậy các phiên bản trước đó có hành vi có khả năng khác nhau.

+0

Tôi không thấy một đọc ngắn.Tôi thấy điều này: Nếu các máy chủ từ xa cuộc gọi tắt máy sau đó đọc của máy chủ địa phương sẽ hoàn thành với eof.Nếu cả hai máy chủ gọi tắt máy sau đó các cuộc gọi để tắt máy sẽ hoàn thành với eof.Đây là ssl :: dòng tắt máy, không TCP/IP tắt máy.Tôi đã viết một bài kiểm tra rằng xác nhận điều này. –

Các vấn đề liên quan