2013-06-03 3 views
6

Попытки справиться с подключенным сокетом клиента в новом потоке из глобального пула потоков:Qt - Ручка QTcpSocket в новом потоке

m_threadPool = QThreadPool::globalInstance(); 

void TCPListenerThread::onNewConnection() 
{ 
    QTcpSocket *clientSocket = m_tcpServer->nextPendingConnection(); 
    clientSocket->localPort(); 
    m_connectThread = new TCPConnectThread(clientSocket); 
    m_threadPool->start(m_connectThread); 
} 

Вот TCPConnectThread:

class TCPConnectThread : public QRunnable { 
    TCPConnectThread::TCPConnectThread(QTcpSocket *_socket) 
    { 
     m_socket = _socket; 
     this->setAutoDelete(false); 
    } 


    void TCPConnectThread::run() 
    { 
     if (! m_socket->waitForConnected(-1)) 
      qDebug("Failed to connect to client"); 
     else 
      qDebug("Connected to %s:%d %s:%d", m_socket->localAddress(), m_socket->localPort(), m_socket->peerAddress(), m_socket->peerPort()); 

     if (! m_socket->waitForReadyRead(-1)) 
      qDebug("Failed to receive message from client") ; 
     else 
      qDebug("Read from client: %s", QString(m_socket->readAll()).toStdString().c_str()); 

     if (! m_socket->waitForDisconnected(-1)) 
      qDebug("Failed to receive disconnect message from client"); 
     else 
      qDebug("Disconnected from client"); 
    } 
} 

Я получал бесконечные ошибки с этими. Кажется, кросс-нить QTcpSocket обработка not feasible (см. Ответ Майкла).

Некоторые ошибки:

QSocketNotifier: socket notifiers cannot be disabled from another thread 

ASSERT failure in QCoreApplication::sendEvent: "Cannot send events t objects owned by a different thread. 

Должен ли я обрабатывать QTcpSocket в другом потоке?
Что делать, если я хочу обрабатывать QTcpSocket в другой теме?
Или есть способ создать QTcpSocket из файлового дескриптора?

ответ

8

Я думаю this page держит ваш ответ:

Если вы хотите обрабатывать входящие соединения в качестве нового объекта QTcpSocket в другом потоке, вы должны пройти socketDescriptor к другому потоку и создать объект QTcpSocket там и используйте свой метод setSocketDescriptor() .

Для этого вам необходимо наследовать от QTcpServer и переопределить виртуальный метод incomingConnection.

В этом методе создайте дочерний поток, который создаст новый дочерний сокет QTcpSocket.

Например:

class MyTcpServer : public QTcpServer 
{ 
protected: 
    virtual void incomingConnection(int socketDescriptor) 
    { 
     TCPConnectThread* clientThread = new TCPConnectThread(socketDescriptor); 
     // add some more code to keep track of running clientThread instances... 
     m_threadPool->start(clientThread); 
    } 
}; 

class TCPConnectThread : public QRunnable 
{ 
private:  
    int m_socketDescriptor; 
    QScopedPointer<QTcpSocket> m_socket; 

public: 
    TCPConnectionThread(int socketDescriptor) 
     : m_socketDescriptor(socketDescriptor) 
    { 
     setAutoDelete(false); 
    } 

protected:  
    void TCPConnectThread::run() 
    { 
     m_socket.reset(new QTcpSocket()); 
     m_socket->setSocketDescriptor(m_socketDescriptor); 

     // use m_socket 
    } 
}; 

или попытаться использовать moveToThread() на сокете.

+0

moveToThread() кажется, работает только с QThread, но я использую QRunnable. – CDT

+1

, затем попробуйте передать 'socketDescriptor' в конструктор' TCPConnectThread' и создать новый 'QTcpSocket' в методе' run' потоков. –

+0

Действительно спасибо! Но я обнаружил, что иногда мне не удается прочитать данные из нового QTcpSocket примерно 1 раз в 10 раз. Понимаете, почему? – CDT

Смежные вопросы