6

SSLクライアントサーバーモデルでは、以下のコードを使用して、クライアント側またはサーバー側のいずれかのソケットからデータを読み取ります。

利用可能なデータがある場合にのみデータを読み取ります。利用可能なデータがいつあるかを知るために、のメソッドを確認しavailable()ます。クライアントからサーバーに380バイトを送信し、サーバーでreadメソッドを入力すると、次のように表示されます。lowest_layer()asio::ssl::stream

's'は私が提供したバッファです。
'n'は、指定したバッファーのサイズです。
'a1'は、読み取り前のavailable()の結果であり、458バイトを報告します。
「r」は実際に読み取られたバイト数です。正しい380を報告します。
'a2'は、読み取り後のavailable()の結果であり、0バイトを報告します。クライアントが380バイトを送信し、それらをすべて読み取ったので、これは私が期待することです。

なぜ最初の呼び出しでavailable()バイト数が多すぎるのですか?

タイプ:

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

メンバー:

ShpSslSocket                     m_shpSecureSocket; 

readメソッドの一部:

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

追加情報:

そこで、readメソッドを変更して、boost :: asio :: ssl::streamから読み取ることができるデータがまだあるかどうかをより徹底的にチェックしました。ソケットレベルで利用可能なデータがあるかどうかを確認する必要があるだけでなく、OpenSSLバッファのどこかにデータがスタックしている可能性もあります。SSL_peekがそのトリックを行います。使用可能なデータのチェックの次に、TCPポートのステータスもチェックし、タイムアウトがない限り、これをすべて実行します。

これが、私が作成したboost :: iostreams::deviceクラスの完全な読み取りメソッドです。

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

1 に答える 1

1

だから多分私はこれがなぜなのか知っています。これは SSL 接続であり、転送されるバイトは暗号化されます。ブロックサイズが原因で、暗号化されたデータのサイズが異なる場合があります。TCPレベルで利用可能なバイト数が、読み取りから得られるバイト数と異なる理由は、これで答えられると思います。

于 2012-10-18T08:19:32.373 に答える