2014-11-26 3 views
5

हमारे पास दो क्यूटी अनुप्रयोग हैं। ऐप 1 एप 2 से QTcpServer से कनेक्शन स्वीकार करता है और इसे QTcpSocket* tcpSocket के उदाहरण में संग्रहीत करता है। ऐप 1 30 हर्ट्ज के साथ सिमुलेशन चलाता है। प्रत्येक सिमुलेशन रन के लिए, एक QByteArray कुछ किलोबाइट से मिलकर (मुख्य/जीयूआई धागे से) निम्नलिखित कोड का उपयोग कर भेज दिया जाता है:छोटे डेटा पैकेजों को लगातार भेजने के लिए QTcpSocket का उपयोग कैसे करें?

QByteArray block; 
    /* lines omitted which write data into block */ 
    tcpSocket->write(block, block.size()); 
    tcpSocket->waitForBytesWritten(1); 

रिसीवर सॉकेट QTcpSocket :: readDataBlock संकेत को सुनता है (मुख्य/जीयूआई में धागा) और जीयूआई के लिए इसी समय टिकट मुद्रित करता है।

जब दोनों एप 1 और ऐप 2 एक ही सिस्टम पर चलते हैं, तो संकुल पूरी तरह सिंक हो जाते हैं। हालांकि जब नेटवर्क के माध्यम से जुड़े विभिन्न सिस्टम पर App1 और App2 चलाए जाते हैं, तो App2 अब App2 में सिमुलेशन के साथ समन्वयित नहीं होता है। पैकेज बहुत धीमे हो जाते हैं। और भी आश्चर्यजनक (और हमारे कार्यान्वयन को इंगित करना गलत है) यह तथ्य है कि जब हम सिमुलेशन लूप को रोकते हैं, तो कोई और पैकेज प्राप्त नहीं होता है। यह हमें आश्चर्यचकित करता है, क्योंकि हम टीसीपी प्रोटोकॉल से अपेक्षा करते हैं कि सभी पैकेज अंततः आ जाएंगे।

हमने क्यूटी के fortune example पर आधारित टीसीपी तर्क बनाया है। हालांकि, भाग्य सर्वर अलग है, क्योंकि यह केवल आने वाले क्लाइंट के लिए एक पैकेज भेजता है। क्या कोई पहचान सकता है कि हमने क्या गलत किया है?

नोट: हम MSVC2012 (App1), MSVC2010 (App2) और Qt 5.2 का उपयोग करते हैं।

संपादित करें: एक पैकेज मैं एक ही अनुकरण प्रयोग है, जो संख्या का एक समूह है, QByteArray block में लिखा का परिणाम मतलब के साथ। हालांकि, पहले बिट्स में QByteArray की लंबाई होती है, ताकि ग्राहक जांच सके कि सभी डेटा प्राप्त हुए हैं या नहीं।

QDataStream in(tcpSocket); 
    in.setVersion(QDataStream::Qt_5_2); 

    if (blockSize == 0) { 
     if (tcpSocket->bytesAvailable() < (int)sizeof(quint16)) 
     return; // cannot yet read size from data block 

     in >> blockSize; // read data size for data block 
    } 

    // if the whole data block is not yet received, ignore it 
    if (tcpSocket->bytesAvailable() < blockSize) 
     return; 

    // if we get here, the whole object is available to parse 
    QByteArray object; 
    in >> object; 

    blockSize = 0; // reset blockSize for handling the next package 

    return; 
+2

टीसीपी संकुल/पैकेट नहीं है - यह सिर्फ एक बाइट धारा है। आपने डेटा को कैसे कटाया है? यानी आपके प्राप्तकर्ता आवेदन को कैसे पता चलेगा जब आपके अपने 1 डेटा "पैकेट" शुरू होते हैं और दूसरा अंत होता है?इसके अलावा, टीसीपी का प्रवाह नियंत्रण होता है, इसलिए यदि आप डेटा पढ़ना बंद कर देते हैं, तो टीसीपी स्टैक में बफर भर जाते हैं, और कोई और डेटा नहीं भेजा जाएगा (और प्रेषक तब तक ब्लॉक करेगा जब तक कि आपके सॉकेट गैर-अवरोध मोड में न हों)। यह अनुमान लगाने में बहुत मुश्किल है कि आप क्या गलत करते हैं जब हम नहीं जानते कि आप क्या करते हैं, या आप सिमुलेशन कैसे काम करते हैं या यह किसी भी तरह से "सिंक से बाहर" कैसे बनता है – nos

+0

मैंने अपने मूल प्रश्न को संपादित करके अपने प्रश्न का उत्तर देने का प्रयास किया। कृपया इसे देखें। –

+0

ऐसा लगता है कि आप जो चाहते हैं उससे अधिक डेटा पढ़ने का जोखिम लेते हैं, उदाहरण के लिए आपका ब्लॉकइज़ 1024 है लेकिन 'tcpSocket-> बाइट्स उपलब्ध()' 1222 बाइट उपलब्ध है, तो आप इसे अगले दिखने के साथ भी अगले ब्लॉक की शुरुआत पढ़ते हैं - तो आपको शायद 'in.readBytes() का उपयोग करना होगा 'इसके बजाय, जहां आप निर्दिष्ट कर सकते हैं कि कितना पढ़ना है। (और बाद में सत्यापित करें कि यह वास्तव में उस डेटा को पढ़ता है)। हालांकि यह भी निर्भर करता है कि आपका प्रोटोकॉल कैसा है। यदि उदा। यह एक साधारण अनुरोध/उत्तर है, जहां आपका प्रेषक * कभी भी * पिछले पैकेट के लिए कोई जवाब प्राप्त नहीं होने तक कोई डेटा भेजता है, वर्तमान कोड ठीक लगता है – nos

उत्तर

5

हमारे कार्यान्वयन में समस्या के कारण हुई थी डेटा संकुल द्वारा ढेर जा रहा है और संकुल जो केवल आंशिक रूप से आया था की गलत हैंडलिंग: इस कोड है जो जब संकेत QTcpSocket :: readDataBlock उत्सर्जित होता है कहा जाता है।

उत्तर Tcp packets using QTcpSocket की दिशा में जाता है। हालांकि इस उत्तर को सीधे तरीके से लागू नहीं किया जा सका, क्योंकि हम सादे QByteArray के बजाय QDataStream पर भरोसा करते हैं।

निम्नलिखित कोड (प्रत्येक बार QTcpSocket::readDataBlock उत्सर्जित होता है) हमारे लिए काम करता है और दिखाता है कि बाइट्स की कच्ची श्रृंखला QDataStream से कैसे पढ़ी जा सकती है। दुर्भाग्यवश ऐसा लगता है कि डेटा को एक स्पष्ट तरीके से संसाधित करना संभव नहीं है (operator>> का उपयोग करके)।

QDataStream in(tcpSocket); 
    in.setVersion(QDataStream::Qt_5_2); 

    while (tcpSocket->bytesAvailable()) 
    { 
     if (tcpSocket->bytesAvailable() < (int)(sizeof(quint16) + sizeof(quint8)+ sizeof(quint32))) 
      return; // cannot yet read size and type info from data block 

     in >> blockSize; 
     in >> dataType; 

     char* temp = new char[4]; // read and ignore quint32 value for serialization of QByteArray in QDataStream  
     int bufferSize = in.readRawData(temp, 4); 
     delete temp; 
     temp = NULL; 

     QByteArray buffer; 

     int objectSize = blockSize - (sizeof(quint16) + sizeof(quint8)+ sizeof(quint32)); 

     temp = new char[objectSize];    
     bufferSize = in.readRawData(temp, objectSize); 
     buffer.append(temp, bufferSize); 
     delete temp; 
     temp = NULL; 

     if (buffer.size() == objectSize) 
     { 
      //ready for parsing    
     } 
     else if (buffer.size() > objectSize) 
     { 
      //buffer size larger than expected object size, but still ready for parsing 
     } 
     else 
     { 
      // buffer size smaller than expected object size 
      while (buffer.size() < objectSize) 
      {    
       tcpSocket->waitForReadyRead(); 
       char* temp = new char[objectSize - buffer.size()];   
       int bufferSize = in.readRawData(temp, objectSize - buffer.size()); 
       buffer.append(temp, bufferSize); 
       delete temp; 
       temp = NULL; 
      } 
      // now ready for parsing 
     } 
     if (dataType == 0) 
     {    
      // deserialize object    
     } 

    } 

कृपया ध्यान दें कि उम्मीद QDataStream के पहले तीन बाइट्स हमारे अपने procotol का हिस्सा हैं: blockSize एक पूर्ण एकल पैकेज के लिए बाइट की संख्या को इंगित करता है, dataType द्विआधारी हिस्सा deserializing मदद करता है।

संपादित , टीसीपी कनेक्शन के माध्यम से वस्तुओं भेजने पैकेट गुच्छन को निष्क्रिय करने के लिए प्रतीक्षा अवधि को कम बहुत उपयोगी था:

// disable Nagle's algorithm to avoid delay and bunching of small packages 
    tcpSocketPosData->setSocketOption(QAbstractSocket::LowDelayOption,1); 
संबंधित मुद्दे