2012-01-28 203 views
1

我有一個QTcpSocket的子類。問題是:當我firt時間連接到服務器 - 一切正常,但套接字連接後,我重新啓動服務器(python socketServer,只需關閉並再次啓動腳本)套接字斷開連接並嘗試重新連接服務器關閉時,但是當我再次啓動服務器 - 什麼都沒有發生,socket.state()總是在ConnectingState中。什麼錯誤?Pyqt;服務器重啓後QTcpSocket總是處於connectedState狀態;

這裏示例代碼:

# -*- coding: utf-8 -*- 
from PyQt4.QtCore import QVariant, QTimer, pyqtSignal, QCoreApplication 
import sys 
from PyQt4.QtNetwork import QTcpSocket 
from re import match 
import json 

MAX_WAIT_LEN = 8 

class UpQSocket(QTcpSocket): 
    data_ready = pyqtSignal(unicode) 
    def __init__(self): 
     QTcpSocket.__init__(self) 
     self.wait_len = '' 
     self.temp = '' 
     self.setSocketOption(QTcpSocket.KeepAliveOption, QVariant(1)) 
     self.readyRead.connect(self.on_ready_read) 
     self.connected.connect(self.on_connected) 
     self.disconnected.connect(self.on_disconnect) 
     self.error.connect(self.on_error) 
     self.data_ready.connect(self.print_command) 

    def connectToHost(self, host, port): 
     print 'connectToHost' 
     self.temp = '' 
     self.wait_len = '' 
     QTcpSocket.abort(self) 
     QTcpSocket.connectToHost(self, host, port) 

    def close(self): 
     print 'close!' 
     self.disconnectFromHost() 

    def send(self, data): 
     self.writeData('%s|%s' % (len(data), data)) 

    def on_ready_read(self): 
     if self.bytesAvailable(): 
      data = str(self.readAll()) 
      while data: 
       if not self.wait_len and '|' in data:#new data and new message 
        self.wait_len , data = data.split('|',1) 
        if match('[0-9]+', self.wait_len) and (len(self.wait_len) <= MAX_WAIT_LEN) and data.startswith('{'):#okay, this is normal length 
         self.wait_len = int(self.wait_len) 
         self.temp = data[:self.wait_len] 
         data = data[self.wait_len:] 
        else:#oh, it was crap 
         self.wait_len , self.temp = '','' 
         return 
       elif self.wait_len:#okay, not new message, appending 
        tl= int(self.wait_len)-len(self.temp) 
        self.temp+=data[:tl] 
        data=data[tl:] 
       elif not self.wait_len and not '|' in data:#crap 
        return 
       if self.wait_len and self.wait_len == len(self.temp):#okay, full message 
        self.data_ready.emit(self.temp) 
        self.wait_len , self.temp = '','' 
        if not data: 
         return 

    def print_command(self,data): 
     print 'data!' 

    def get_sstate(self): 
     print self.state() 

    def on_error(self): 
     print 'error', self.errorString() 
     self.close() 
     self.connectToHost('dev.ulab.ru', 10000) 

    def on_disconnect(self): 
     print 'disconnected!' 

    def on_connected(self): 
     print 'connected!' 
     self.send(json.dumps(
       {'command' : "operator_insite", 
       'password' : "376c43878878ac04e05946ec1dd7a55f", 
       'login' : "nsandr", 
       'version':unicode("1.2.9")})) 

if __name__ == "__main__": 
    app = QCoreApplication(sys.argv) 
    main_socket = UpQSocket() 
    state_timer = QTimer() 
    state_timer.setInterval(1000) 
    state_timer.timeout.connect(main_socket.get_sstate) 
    state_timer.start() 
    main_socket.connectToHost('dev.ulab.ru', 10000) 
    sys.exit(app.exec_()) 

這裏是輸出:

connectToHost 
    1 
    1 
connected! 
data! 
data! 
3 
3 
3 
3 
3 
error The remote host closed the connection 
close! 
disconnected! 
connectToHost 
2 
2 
+0

我認爲它試圖建立連接,並等待超時,這在默認情況下很大。也許你可以通過檢查'QTcpSocket.waitForConnected(smallTiemout)'來重試連接。 – reclosedev 2012-01-28 08:34:49

+0

嗯,這工作對我來說,但只有一次和套接字斷開立即.. – 2012-01-28 09:09:11

+0

是的,這是錯誤的建議。它與事件系統有某種關係,但我無法弄清楚。無論如何,請參閱我的答案中的解決方法。這個對我有用。 – reclosedev 2012-01-28 10:26:27

回答

3

解決方法:

import functools 

def on_error(self): 
    print 'error', self.errorString() 
    QTimer.singleShot(2000, functools.partial(self.connectToHost, 'localhost', 9999)) 
    # 2000 - your prefered reconnect timeout in ms 

更新

對於Qt bugreport QTBUG-18082,有更正確的解決方案。下面是Python實現:

@QtCore.pyqtSlot() 
def do_reconnect(self): 
    print 'Trying to reconnect' 
    self.connectToHost('localhost', 9999) 

def on_error(self): 
    print 'error', self.errorString() 
    QtCore.QMetaObject.invokeMethod(self, 'do_reconnect', QtCore.Qt.QueuedConnection) 

或者只是:

QTimer.singleShot(0, self.do_reconnect) # or any callable, slot is unnecessary 

這無論如何將調用QtCore.QMetaObject.invokeMethodQueuedConnection連線類型(source

+0

是的,它的工作,謝謝,但有幾個問題:爲什麼我們需要通過pyqtSlot()裝飾它明確定義槽?爲什麼我們需要像這樣調用方法?(通過QMetaObject)。謝謝。 – 2012-01-29 19:43:26

+1

@Andrewshkovskii,我們需要明確定義槽位,因爲invokeMethod會按字符串在他的方法表中搜索它。 '@pyqtSlot()'裝飾器在metaobject中註冊我們的方法。我們需要以這種方式調用方法,因爲我們處於'on_error'處理程序中,並且我們必須將控制權返回給應用程序主循環。順便說一句,[QTimer.singleShot(0,self.do_recconect)](http://qt.gitorious.org/qt/qt/blobs/master/src/corelib/kernel/qtimer.cpp#line351)將調用'QMetaObject。 invokeMethod'。它接受沒有插槽定義的Python方法/可調用。 – reclosedev 2012-01-30 14:50:10

+0

感謝您的解釋。 – 2012-01-30 19:26:15

相關問題