天天看點

Qt 線程中使用socket(勘誤)

之前寫過兩篇關于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));
}           

複制

三、程式運作效果:

Qt 線程中使用socket(勘誤)

Server 的初始化在新的線程中(1),接受用戶端連接配接也在新的線程中(2)。

Qt 線程中使用socket(勘誤)

Client 的初始化在新的線程中(1),接收伺服器資料也在新的線程中(2)。