2012-05-04 6 views
24

मेरे पास एक QTcpSocket है और मैं एक लूप में पढ़ रहा हूं। हर बार एक पूर्ण पैकेट पढ़ कर दिया गया है, या कोई त्रुटि हुई है, मैं मैन्युअल सॉकेट की स्थिति पाश अंदर के साथ जांच,:QTcpSocket स्थिति हमेशा कनेक्ट होती है, यहां तक ​​कि अनप्लगिंग ईथरनेट वायर

while(true){ 
    if(socket->state()==QAbstractSocket::ConnectedState){ 
     qDebug()<<"Socket status: connected. Looking for packets..."; 
     if(socket->waitForReadyRead(2000)){ 
     //... 
    } 

जब मैं डी कार्यक्रम, एक बार जुड़े निष्पादित और पाश शुरू होता है, यह हमेशा qDebug()<<"Socket status: connected. Looking for packets..." प्रिंट करता है; और उसके बाद waitForReadyRead पर अटक जाता है जब तक कि कुछ डेटा पढ़ने के लिए तैयार नहीं होता है।

समस्या यह है कि डिस्कनेक्शन का पता नहीं लगाया गया है। यदि मैं ओएस विकल्पों से नेटवर्क से डिस्कनेक्ट करता हूं, या यदि मैं ईथरनेट तार को अनप्लग करता हूं, तो यह वही व्यवहार करता है: सॉकेट स्थिति QAbstractSocket::ConnectedStat ई के बराबर होती है, इसलिए यह चलती है, लेकिन बिना किसी कोर्स के प्राप्त होती है।

मैं भी एक पुनः कनेक्ट कार्य करने के लिए (मुट्ठी कनेक्शन के बाद) disconnected() संकेत जोड़ने डिस्कनेक्शन का पता लगाने की कोशिश की:

// Detect disconnection in order to reconnect 
    connect(socket, SIGNAL(disconnected()), this, SLOT(reconnect())); 

void MyClass::reconnect(){ 
    qDebug()<<"Signal DISCONNECTED emitted. Now trying to reconnect"; 
    panelGUI->mostrarValueOffline(); 
    socket->close(); 
    prepareSocket((Global::directionIPSerialServer).toLocal8Bit().data(), 8008, socket); 
    qDebug()<<"Reconnected? Status: "<<socket->state(); 
} 

लेकिन संकेत, उत्सर्जित कभी नहीं है क्योंकि यह कोड निष्पादित कभी नहीं किया गया है। जो तार्किक है, क्योंकि ऐसा लगता है कि सॉकेट स्थिति हमेशा ConnectedState है।

यदि मैं दोबारा प्लग करता हूं, कनेक्शन बहाल हो जाता है और फिर डेटा प्राप्त करना शुरू होता है, लेकिन मैं GUI पर "डिस्कनेक्ट" दिखाने के लिए डिस्कनेक्शन का पता लगाना चाहता हूं।

QTcpSocket इस तरह से क्यों व्यवहार कर रहा है, और मैं इस समस्या को कैसे हल कर सकता हूं?

संपादित करें: मैं कक्षा निर्माता पर सॉकेट बना रहा हूं, और फिर बुला prepareSocket समारोह initialising:

socket = new QTcpSocket(); 
socket->moveToThread(this); 

bool prepareSocket(QString address, int port, QTcpSocket *socket) { 
    socket->connectToHost(address, port); 
    if(!socket->waitForConnected(2000)){ 
     qDebug()<<"Error creating socket: "<<socket->errorString(); 
     sleep(1); 
     return false; 
    } 
    return true; 
} 
+2

केबल अनप्लग किए गए आप कितने समय तक प्रतीक्षा करते थे? – Mat

+0

पता नहीं ... 10 सेकंड? POSIX सॉकेट के लिए यह निर्धारित करने के लिए बहुत कम आवश्यक था कि वे डिस्कनेक्ट हो गए थे। मुझे कितना इंतजार करना चाहिए? –

+0

टीसीपी टाइमआउट उस से ऊपर हैं। कम से कम कुछ मिनट के लिए प्रतीक्षा करें। – Mat

उत्तर

20

अंत में इस Qt forum में समाधान नहीं मिला:

कोई डेटा एक निश्चित समय के लिए आदान-प्रदान किया जाता है, तो टीसीपी होगा रख-रखाव सेगमेंट भेजना शुरू करें (मूल रूप से, स्वीकृति संख्या के साथ एसीके सेगमेंट वर्तमान अनुक्रम संख्या को कम सेट करें)। अन्य सहकर्मी फिर एक और पावती के साथ जवाब देता है। यदि यह पावती जांच खंडों की एक निश्चित संख्या के भीतर प्राप्त नहीं होती है, तो कनेक्शन स्वचालित रूप से गिरा दिया जाता है। छोटी समस्या यह है कि कर्नेल 2 घंटे बाद रख-रखाव सेगमेंट भेजता है जब कनेक्शन निष्क्रिय हो जाता है! इसलिए, आपको यह मान बदलने की जरूरत है (यदि आपका ओएस इसकी अनुमति देता है) या अपने प्रोटोकॉल में अपने स्वयं के जीवित तंत्र को लागू करें (जैसे कई प्रोटोकॉल करते हैं, जैसे एसएसएच)।

int enableKeepAlive = 1; 
int fd = socket->socketDescriptor(); 
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive)); 

int maxIdle = 10; /* seconds */ 
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle)); 

int count = 3; // send up to 3 keepalive packets out, then disconnect if no response 
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &count, sizeof(count)); 

int interval = 2; // send a keepalive packet out every 2 seconds (after the 5 second idle period) 
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(interval)); 
+4

किसी और के लिए यह कोशिश कर रहा है: '# शामिल # शामिल करें # शामिल करें ' – kwahn

+1

क्या यह कोड आपके द्वारा बनाए जाने के ठीक बाद चला जाता है QTcpSocket? और तुम क्यूटी के सॉकेट पर इन विकल्प के सेट करने के लिए एक और फ़ंक्शन को कॉल करने की क्या ज़रूरत है (या वे तुरंत क्यूटी सॉकेट से प्रभावी करते हैं)। – TSG

0

क्यूटी में ग्राहक की मेरे टेम्पलेट का प्रयास करें:

class Client: public QTcpSocket { 
    Q_OBJECT 
public: 
    Client(const QHostAddress&, int port, QObject* parent= 0); 
    ~Client(); 
    void Client::sendMessage(const QString&); 
private slots: 
    void readyRead(); 
    void connected(); 
public slots: 
    void doConnect(); 
}; 
सीपीपी पर

:

void Client::readyRead() { 

    // if you need to read the answer of server.. 
    while (this->canReadLine()) { 
    } 
} 

void Client::doConnect() { 
    this->connectToHost(ip_, port_); 
    qDebug() << " INFO : " << QDateTime::currentDateTime() 
      << " : CONNESSIONE..."; 
} 

void Client::connected() { 
    qDebug() << " INFO : " << QDateTime::currentDateTime() << " : CONNESSO a " 
      << ip_ << " e PORTA " << port_; 
    //do stuff if you need 
} 


void Client::sendMessage(const QString& message) { 
    this->write(message.toUtf8()); 
    this->write("\n"); //every message ends with a new line 
} 

मैंने कुछ कोड कन्स्ट्रक्टर और स्लॉट कनेक्शन के रूप में छोड़ा .. इस के साथ कोशिश करते हैं और अगर यह काम नहीं करता हो सकता है कि वहाँ कुछ सर्वर साइड पर गलत है ..

+0

मुझे यकीन है कि यह काम करता है, यह मेरे पास कम या ज्यादा है। लेकिन कनेक्शन पहले से ही काम करता है, जो मैं चाहता हूं डिस्कनेक्शन का पता लगाना है, और यह आपके टेम्पलेट पर भी नहीं हो रहा है।इसके अलावा, सर्वर साइड आप 'शून्य QAbstractSocket :: disconnectFromHost()' कहीं का उपयोग करते हैं, क्योंकि यह POSIX सॉकेट –

+0

के साथ काम किया ठीक है? –

10

मैं एक क्यूटी ग्राहक अनुप्रयोग के साथ इसी तरह की समस्याओं का सामना करना पड़ रहा है: लिनक्स परिवर्तन यह setsockopt उपयोग करने के लिए आपको अनुमति देता है। असल में मैं इसे टाइमर, सिग्नल और स्लॉट के साथ संभालता हूं। जब ऐप शुरू होता है, तो यह 4 सेकंड चेककनेक्शन टाइमर शुरू करता है। हर 4 सेकंड टाइमर समाप्त हो रहा है, अगर ग्राहक सॉकेट राज्य! = AbstractSocket :: कनेक्ट किया गया या कनेक्ट, इसके साथ clientSocket-> connectToHost

कनेक्ट करने का प्रयास सॉकेट संकेत "जुड़ा हुआ()", यह एक 5 सेकंड सर्वर शुरू होता है दिल की धड़कन टाइमर। सर्वर को हर 4 सेकंड में अपने ग्राहकों को एक बाइट दिल की धड़कन संदेश भेजना चाहिए। जब मुझे दिल की धड़कन मिलती है (या तैयार रीड() द्वारा संकेतित किसी भी प्रकार का संदेश), मैं दिल की धड़कन टाइमर को पुनरारंभ करता हूं। तो यदि दिल की धड़कन टाइमर में कभी भी टाइमआउट होता है, तो मुझे लगता है कि कनेक्शन डाउन हो जाएगा और यह clientSocket->disconnectFromHost();

यह सर्वर पर सभी प्रकार के डिस्कनेक्ट, सुंदर या अन्यथा (यांकिंग केबल) के लिए बहुत अच्छा काम कर रहा है। हां इसे कस्टम दिल की धड़कन प्रकार की आवश्यकता होती है, लेकिन दिन के अंत में यह सबसे तेज़ और सबसे पोर्टेबल समाधान था।

मैं कर्नेल में केपैलिव टाइमआउट सेट करने के लिए उत्सुक नहीं था। इस तरह यह और अधिक पोर्टेबल। निर्माता में:

connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));

स्लॉट कार्यान्वयन पर:

connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readMessage())); 
connect(clientSocket, SIGNAL(connected()), this, SLOT(socketConnected())); 
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); 
connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(serverTimeout())); 
... 
// Other Methods 

void NetworkClient::checkConnection(){ 
    if (clientSocket->state() != QAbstractSocket::ConnectedState && 
      clientSocket->state() != QAbstractSocket::ConnectingState){ 
     connectSocketToHost(clientSocket, hostAddress, port); 
    } 
} 

void NetworkClient::readMessage() 
{ 
    // Restart the timer by calling start. 
    heartbeatTimer->start(5000); 
    //Read the data from the socket 
    ... 
} 

void NetworkClient::socketConnected(){ 
    heartbeatTimer->start(5000); 
} 

void NetworkClient::socketDisconnected(){ 
    prioResponseTimer->stop(); 
} 

void NetworkClient::serverTimeout() { 
    clientSocket->disconnectFromHost(); 
} 
+0

मैंने पृष्ठ पर सभी उत्तरों की कोशिश की। यह एकमात्र ऐसा है जो मेरे लिए काम करता है। – kwahn

+0

क्या हुआ अगर नेटवर्क, ओवरलोड हो गया है और (दिल की धड़कन) पैकेट की तरह के लिए 2 या 3 senconds देरी हो गई, और उसके बाद आता है? – Xsmael

1

इस संकेत स्लॉट कनेक्शन की कोशिश

void TCPWorker::onStateChanged(QAbstractSocket::SocketState socketState){ 
qDebug()<< "|GSTCPWorkerThread::onStateChanged|"<<socketState; 
...} 

मैं एक ही समस्या है, लेकिन इसके बजाय आपकी समस्या (हमेशा जुड़ा हुआ), ईथरनेट तार को अनप्लग करने के बाद, डिस्कनेक्ट सिग्नल प्राप्त करने के लिए मुझे 4-5 सेकंड में देरी हुई है।

अभी भी समाधान ढूंढ रहे हैं, अगर उत्तर मिलते हैं तो उत्तर पोस्ट करें।

+3

दूसरों को पढ़ने के लिए, यह काम नहीं करता है। ऑनस्टेट चेंज() तार को अनप्लग होने पर नहीं कहा जाता है। – kwahn

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