2012-10-18 13 views
6

W modelu serwera klienta SSL używam poniższego kodu do odczytu danych z gniazda po stronie klienta lub serwera.Wzmocnienie asio Gniazdo tcp dostępne raporty niepoprawna liczba bajtów

Czytam dane tylko wtedy, gdy są dostępne dane. Aby wiedzieć, kiedy są dostępne dane, sprawdzam metodę available() na lowest_layer() z asio::ssl::stream. Po wysłaniu 380 bajtów z klienta na serwer i wprowadzeniu metody odczytu na serwerze, widzę co następuje.

's' to bufor, który dostarczyłem.
'n' jest wielkością bufora, który dostarczyłem.
"a1" jest wynikiem dostępnej() przed odczytem i wyświetli 458 bajtów.
"r" to liczba faktycznie przeczytanych bajtów. Zgłasza 380, co jest poprawne.
'a2' jest wynikiem dostępnej() po przeczytaniu i będzie raportować 0 bajtów. Tego właśnie oczekuję, ponieważ mój klient wysłał 380 bajtów i przeczytałem je wszystkie.

Dlaczego pierwsze połączenie z numerem available() zgłasza zbyt wiele bajtów?

Typy:

/** 
* 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; 

Użytkownicy:

ShpSslSocket      m_shpSecureSocket; 

częścią metody odczytu:

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(); 

Dodany info:

Zmieniłem metodę odczytu, aby dokładniej sprawdzić, czy wciąż dostępne są dane do odczytu z boost :: asio :: ssl :: stream. Muszę nie tylko sprawdzić, czy są dostępne dane na poziomie gniazd, ale mogą również znajdować się dane zablokowane w buforze OpenSSL. SSL_peek załatwia sprawę. Obok sprawdzania dostępnych danych sprawdza również status portu TCP i robi to wszystko, dopóki nie ma limitu czasu.

Oto kompletna metoda odczytu klasy boost :: iostreams ::, którą utworzyłem.

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

wydaje się to zbyt skomplikowane, dlaczego nie użyć opcji 'async_read()' i pozwolić na odpytywanie instrukcji 'io_service'? –

Odpowiedz

1

Może więc wiem, dlaczego tak jest. Jest to połączenie SSL i term przenoszonych bajtów będzie szyfrowane. Zaszyfrowane dane mogą mieć inny rozmiar ze względu na rozmiar bloku. Przypuszczam, że odpowiada na pytanie, dlaczego liczba bajtów dostępnych na poziomie TCP jest inna niż liczba bajtów, które pochodzą z odczytu.

+0

SSL_peek powinien być również użyty do sprawdzenia liczby dostępnych bajtów do odczytania. –

Powiązane problemy