6

在 SSL 客户端服务器模型中,我使用下面的代码从客户端或服务器端的套接字读取数据。

我只在有可用数据时读取数据。要知道何时有可用数据,我检查available()lowest_layer(). asio::ssl::stream在我从客户端向服务器发送 380 字节并在服务器上输入读取方法后,我看到以下内容。

'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; 

部分读取方法:

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

添加信息:

所以我改变了我的读取方法来更彻底地检查是否还有数据可以从 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 回答