2012-10-18 29 views
6

Trong mô hình máy chủ ứng dụng khách SSL, tôi sử dụng mã bên dưới để đọc dữ liệu từ ổ cắm ở phía máy khách hoặc phía máy chủ.Tăng các ổ cắm asc tcp có sẵn báo cáo số byte không chính xác

Tôi chỉ đọc dữ liệu khi có sẵn dữ liệu. Để biết khi có dữ liệu, tôi kiểm tra phương thức available() trên lowest_layer() của số asio::ssl::stream. Sau khi tôi gửi 380 byte từ máy khách đến máy chủ và nhập phương thức đọc trên máy chủ, tôi thấy như sau.

‘s’ là bộ đệm tôi đã cung cấp.
‘n’ là kích thước của bộ đệm tôi đã cung cấp.
‘a1’ là kết quả có sẵn() trước khi đọc và sẽ báo cáo 458 byte.
‘r’ là số byte thực sự đọc. Nó sẽ báo cáo 380, đó là chính xác.
‘a2’ là kết quả của có sẵn() sau khi đọc và sẽ báo cáo 0 byte. Đây là những gì tôi mong đợi, kể từ khi khách hàng của tôi gửi 380 byte và tôi đã đọc tất cả.

Tại sao cuộc gọi đầu tiên đến available() báo cáo quá nhiều byte?

loại:

/** 
* Type used as SSL Socket. Handles SSL and socket functionality. 
*/ 
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SslSocket; 
/** 
* A shared pointer version of the SSL Socket type. 
*/ 
typedef boost::shared_ptr<SslSocket>       ShpSslSocket; 

Thành viên:

ShpSslSocket      m_shpSecureSocket; 

Một phần của phương pháp đọc:

std::size_t a1 = 0; 
if ((a1 = m_shpSecureSocket->lowest_layer().available()) > 0) 
{ 
    r += boost::asio::read(*m_shpSecureSocket, 
          boost::asio::buffer(s, n), 
          boost::asio::transfer_at_least(1)); 
} 

std::size_t a2 = m_shpSecureSocket->lowest_layer().available(); 
thông tin

Added:

Vì vậy, tôi đã thay đổi phương pháp đọc của mình để kiểm tra kỹ hơn nếu vẫn có dữ liệu để đọc từ luồng tăng :: asio :: ssl ::. Tôi không chỉ cần kiểm tra xem có dữ liệu có sẵn ở cấp ổ cắm hay không, nhưng cũng có thể có dữ liệu bị kẹt trong bộ đệm OpenSSL ở đâu đó. SSL_peek thực hiện thủ thuật. Bên cạnh việc kiểm tra dữ liệu có sẵn, nó cũng kiểm tra trạng thái cổng TCP và thực hiện tất cả điều này miễn là không có thời gian chờ.

Đây là phương pháp đọc đầy đủ của tăng :: iostreams :: lớp thiết bị mà tôi đã tạo.

std::streamsize SslClientSocketDevice::read(char* s, std::streamsize n) 
{ 
    // Request from the stream/device to receive/read bytes. 
    std::streamsize r = 0; 

    LIB_PROCESS::TcpState eActualState = LIB_PROCESS::TCP_NOT_EXIST; 

    char chSslPeekBuf; // 1 byte peek buffer 

    // Check that there is data available. If not, wait for it. 
    // Check is on the lowest layer (tcp). In that layer the data is encrypted. 
    // The number of encrypted bytes is most often different than the number 
    // of unencrypted bytes that would be read from the secure socket. 
    // Also: Data may be read by OpenSSL from the socket and remain in an 
    // OpenSSL buffer somewhere. We also check that. 
    boost::posix_time::ptime start = BOOST_UTC_NOW; 
    int   nSslPeek = 0; 
    std::size_t nAvailTcp = 0; 
    while ((*m_shpConnected) && 
      (LIB_PROCESS::IpMonitor::CheckPortStatusEquals(GetLocalEndPoint(), 
                 GetRemoteEndPoint(), 
                 ms_ciAllowedStates, 
                 eActualState)) && 
      ((nAvailTcp = m_shpSecureSocket->lowest_layer().available()) == 0) && 
      ((nSslPeek = SSL_peek(m_shpSecureSocket->native_handle(), &chSslPeekBuf, 1)) <= 0) && // May return error (<0) as well 
      ((start + m_oReadTimeout) > BOOST_UTC_NOW)) 
    { 
     boost::this_thread::sleep(boost::posix_time::millisec(10)); 
    } 

    // Always read data when there is data available, even if the state is no longer valid. 
    // Data may be reported by the TCP socket (num encrypted bytes) or have already been read 
    // by SSL and not yet returned to us. 
    // Remote party can have sent data and have closed the socket immediately. 
    if ((nAvailTcp > 0) || (nSslPeek > 0)) 
    { 
     r += boost::asio::read(*m_shpSecureSocket, 
          boost::asio::buffer(s, n), 
          boost::asio::transfer_at_least(1)); 
    } 

    // Close socket when state is not valid. 
    if ((eActualState & ms_ciAllowedStates) == 0x00) 
    { 
     LOG4CXX_INFO(LOG4CXX_LOGGER, "TCP socket not/no longer connected. State is: " << 
            LIB_PROCESS::IpMonitor::TcpStateToString(eActualState)); 
     LOG4CXX_INFO(LOG4CXX_LOGGER, "Disconnecting socket."); 
     Disconnect(); 
    } 

    if (! (*m_shpConnected)) 
    { 
     if (r == 0) 
     { 
     r = -1; // Signal stream is closed if no data was retrieved. 
     ThrowExceptionStreamFFL("TCP socket not/no longer connected."); 
     } 
    } 

    return r; 
} 
+1

điều này có vẻ quá phức tạp, tại sao không sử dụng 'async_read() 'và cho phép xử lý cuộc thăm dò' io_service'? –

Trả lời

1

Vì vậy, có lẽ tôi biết tại sao điều này xảy ra. Đây là kết nối SSL và các byte được chuyển sẽ được mã hóa. Dữ liệu được mã hóa có thể có kích thước khác vì kích thước khối. Tôi đoán rằng câu trả lời cho câu hỏi tại sao số lượng byte có sẵn trên cấp TCP khác với số byte xuất phát từ đọc.

+0

SSL_peek cũng nên được sử dụng để kiểm tra số byte có sẵn để đọc. –

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