2012-10-18 11 views
6

एसएसएल क्लाइंट सर्वर मॉडल में, मैं क्लाइंट या सर्वर पक्ष पर सॉकेट से डेटा पढ़ने के लिए नीचे दिए गए कोड का उपयोग करता हूं।बूस्ट एएसआईओ टीसीपी सॉकेट उपलब्ध रिपोर्ट्स बाइट्स की गलत संख्या

डेटा उपलब्ध होने पर मैं केवल डेटा पढ़ता हूं। यह जानने के लिए कि डेटा उपलब्ध होने पर, के lowest_layer() पर available() विधि की जांच करें। जब मैं क्लाइंट से सर्वर पर 380 बाइट भेजता हूं और सर्वर पर रीड विधि दर्ज करता हूं, तो मुझे निम्न दिखाई देता है।

'' बफर मैंने प्रदान किया है।
'एन' मैं प्रदान किए गए बफर का आकार है।
'ए 1' पढ़ने से पहले उपलब्ध() का परिणाम है और 458 बाइट्स की रिपोर्ट करेगा।
'आर' वास्तव में बाइट्स की संख्या को पढ़ा जाता है। यह 380 की रिपोर्ट करेगा, जो सही है।
'ए 2' पढ़ने के बाद उपलब्ध() का परिणाम है और 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(); 

जोड़ा जानकारी:

तो मैंने बूस्ट :: asio :: ssl :: स्ट्रीम से पढ़ने के लिए अभी भी उपलब्ध डेटा को देखने के लिए मेरी पढ़ाई विधि को और अधिक अच्छी तरह से जांचने के लिए बदल दिया है। मुझे केवल यह जांचने की ज़रूरत नहीं है कि सॉकेट स्तर पर डेटा उपलब्ध है या नहीं, लेकिन ओपनएसएसएल बफर में कहीं भी डेटा फंस सकता है। SSL_peek चाल करता है। उपलब्ध डेटा की जांच करने के बाद, यह टीसीपी बंदरगाह की स्थिति भी जांचता है और यह तब तक करता है जब तक कोई टाइमआउट नहीं होता है।

यहां निर्मित :: iostreams :: डिवाइस क्लास की पूरी पढ़ी गई विधि है।

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

यह अत्यधिक जटिल लगता है, क्यों 'async_read() 'का उपयोग न करें और' io_service' मतदान को संभालने दें? –

उत्तर

1

तो शायद मुझे पता है कि यह क्यों है। यह एक एसएसएल कनेक्शन है और ट्रांसफर बाइट्स के लिए थर्मल एन्क्रिप्ट किया जाएगा। ब्लॉक आकार की वजह से एन्क्रिप्टेड डेटा एक अलग आकार का हो सकता है। मुझे लगता है कि सवाल का जवाब क्यों टीसीपी स्तर पर उपलब्ध बाइट्स की संख्या एक पढ़ने से बाहर बाइट्स की संख्या से अलग है।

+0

SSL_peek का उपयोग भी उपलब्ध बाइट्स की संख्या को पढ़ने के लिए किया जाना चाहिए। –

संबंधित मुद्दे