返回

Qt 线程中使用socket

Qt中将socket放到线程中运行目前我知道比较好的方式还是使用MoveToThread。不过要注意的是只有slot_initSocket()槽中的函数是运行在新的线程中的。就像继承QThread重新实现run()函数一样,只有run()里面的是运行在线程中一样。

程序示例:

    m_socketClient.moveToThread(&m_thread);

    connect(&m_thread, SIGNAL(started()), &m_socketClient, SLOT(slot_initSocket()));

    m_thread.start();

经过Qt封装的socket我们使用起来非常方便,有数据到来可以读取后就会触发槽函数,如果使用继承QThread重新实现run()函数的方式,就会不可避免的遇到无法舒服使用信号和槽的情况。而使用MoveToThread则可以规避上面的问题——我们将socket的初始化放到slot_initSocket()函数中,则socket的初始化则是在线程中完成的,那么对应里面信号和槽的连接也是运行在新线程中的。

程序示例:

connect(mp_clsTcpSocket,SIGNAL(readyRead()),this,SLOT(slot_recvServerData()));

经过上面的操作,我们的socket就可以运行在线程中了。Qt官方也非常推荐使用moveToThread函数。

示例程序是之前socket拆包、处理粘包程序的修改,大家有兴趣可以了解下。服务器端是接收图片、客户端发送图片,下面程序是客户端部分。

老规矩,贴下程序,方便理解:

一、继承QObject的socket 客户端程序

MySocketClient::MySocketClient(QObject *parent) : QObject(parent)
{
    mp_clsTcpSocket = new QTcpSocket(this);
}

void MySocketClient::slot_recvServerData()
{
    QByteArray data = mp_clsTcpSocket->readAll();

    qDebug() << "------------" << data;
    qDebug() << "socket recv thread id:" << QThread::currentThreadId();}

void MySocketClient::slot_writeData(QByteArray str)
{
    mp_clsTcpSocket->write(str);
}

void MySocketClient::slot_initSocket()
{
    qDebug() << "socket thread id:" << QThread::currentThreadId();

    mp_clsTcpSocket->connectToHost("127.0.0.1",8002);
    mp_clsTcpSocket->waitForConnected(1000);

    connect(mp_clsTcpSocket,SIGNAL(readyRead()),this,SLOT(slot_recvServerData()));
}

二、主线程函数

①构造函数中使用moveToThread

 m_socketClient.moveToThread(&m_thread);
    connect(&m_thread, SIGNAL(started()), &m_socketClient, SLOT(slot_initSocket()));
    m_thread.start();

    connect(this, SIGNAL(signal_sendPicrure(QByteArray)),
            &m_socketClient,SLOT(slot_writeData(QByteArray)));
            

②主Ui线程通过信号和槽使用线程中的socket发送数据

void Widget::on_pbn_send_clicked()
{
    QString str = "i am from server of main ui";
    emit (signal_sendData(str));
}


Client 的初始化在新的线程中(1),接收服务器数据也在新的线程中(2)。

相关知识