如何在多线程中使用QTcpSocket?

时间:2016-02-24 02:24:48

标签: c++ multithreading qt

在上一个问题中,我没有清楚地表达我的用例。现在我描述我的要求。 在我的客户端,我需要使用QTcpSocket连接到服务器。在大多数情况下,我可以在gui线程(主线程)中编写和读取。 但是,在一些耗时的任务中,我需要一个工作线程来执行任务。当我用gui线程连接服务器时,我一直保持连接。 如果我在工作线程中使用新的QTcpSocket,我必须断开gui线程中的套接字吗?并再次连接到服务器?

class Widget:public QWidget
{
    Q_OBJECT
public:
    Widget()
    {
        socket = new QTcpSocket(this);
    }   
private:
    QHostAddress host;
    unsigned int port;
    QTcpSocket *socket;
private slots:  
    void startConnect()
    {
        socket->connectToHost(host,port);
    }
    void sendData()
    {
        //just send some bytes
        //socket->write();
    }
    void doTimeConsumingTask()
    {
        //must i disconnect gui->socket connection before the Worker is running?
        // socket->disconnectFromHost();
        Worker * w = new Worker();
        w->start();
    }
}

class Worker:public QThread
{
    Q_OBJECT
public:
    Worker()
    {

    }
protected:
    void run()
    {
        QTcpSocket socket;
        // must i connectToHost again here ? 


        // do something consuming time
        while(true){
            //
            QThread::msleep(10);

        }
    }
private:
    QHostAddress host;
    unsigned int port;
}

2 个答案:

答案 0 :(得分:0)

解决问题的简单方法是不直接从工作线程访问QTcpSocket。最终,您可能想要使用来自工作线程的套接字来向它发送和/或接收数据。在这种情况下,您可以让工作线程发出带有QByteArray参数的信号,然后将该信号连接到GUI线程上的插槽,然后在QTcpSocket上调用write(const QByteArray& byteArray)。类似地,您可以使用数据接收函数(无论连接到套接字的readyRead()信号)是存在于工作线程中,还是存在于主线程中,但是在收到工作线程需要处理的数据时,通过信号/插槽连接传递数据。

另一种选择,如果你必须直接访问套接字(比如,你需要做的不仅仅是写入它,也许你必须能够关闭它或其他什么),你需要将每个套接字的使用包装在一个套接字中。 mutex,在两个线程上。这可能是最好的方法是将原始QTcpSocket包装在另一个只暴露你需要的几个方法的类中,并且总是有一个调用: QMutexLocker locker(theMutex); 在每个函数的开头。

答案 1 :(得分:-2)

有没有理由你不能将套接字传递给线程的构造函数?

class Worker : public QThread{
public:
    Worker(QTcpSocket* pSocket) : m_pSocket(pSocket) ...

不确定您的使用案例,但是有理由不能这样做吗?

来自文档:http://doc.qt.io/qt-4.8/qiodevice.html

QIODevice的某些子类,例如QTcpSocket和QProcess,是异步的。这意味着诸如write()或read()之类的I / O函数总是立即返回,而当控制返回到事件循环时,可能会发生与设备本身的通信。 QIODevice提供的功能允许您强制立即执行这些操作,同时阻止调用线程并且不进入事件循环。这允许在没有事件循环的情况下使用QIODevice子类,或者在单独的线程中使用: