QT之TCP客戶端執行緒通訊

2021-08-07 02:04:04 字數 3702 閱讀 6759

最近因為工作上的需求要利用到tcp,之前接觸的比較多的是c語言的tcp通訊,轉到qt之後多多少少有些不適應,因為qt把tcp通訊的功能封裝好了。讓我們一起看看tcp客戶端加上執行緒是如何實現的。

因為c語言的影響,我會首選執行緒來實現tcp客戶端。因為gui程式設計下不知道程序是否操作的好這是其一,

其二是因為執行緒與程序相比對系統的資源開銷比較小,利於優化,減少介面的卡頓提高使用者體驗這是很重要

的一點。然後就是gui下執行緒會迴圈執行,因此把客戶端的連線功能扔給執行緒去做再合適不過了。這樣次客

戶端就能主動的連線伺服器端,就算連線失敗也能繼續重連。

我使用的是qt5版本,所以也只討論qt5,看過網上各位大牛的總結後我才領悟到,qt下的執行緒是如何建立的。

首先你得在.pro工程檔案裡

qt       += network

//然後再

#include

#include

#include

兩種方法:

m_thread =

new qthread(); //建立乙個執行緒

m_smu =

new smuthread(); //你自己寫的乙個類

m_smu->movetothread(m_thread); //把m_smu的類扔到執行緒裡,讓它去跑

m_thread->start(); //執行緒開始

第一種繼承class timethread : public qthread

是繼承thread類 這樣寫法要注意的是,run()函式裡面才是執行緒執行的地方,因此如果要迴圈常搭配while(1)。

任何繼承於qthread的執行緒都是通過繼承qthread的run函式來實現多執行緒的,因此,必須重寫qthread的run函式,把複雜邏輯寫在qthread的run函式中。

qthread在不呼叫exec()情況下是exit函式和quit函式是沒有作用的,要馬上終止乙個執行緒可以使用terminate函式,但這個函式存在非常不安定因素,不推薦使用。當run()函式返回的以後,執行緒會退出(exit)。如果沒有呼叫exec()函式,該執行緒中不存在任何執行狀態的事件迴圈(event loop)。

正確的方法是自己在run()函式裡面加乙個bool來進行判斷,修改bool型別的時候要加鎖。這也大多數要修改執行緒引數普遍常用的方法。繼承qthread的函式在執行完run函式後就視為執行緒完成,會發射finish訊號。

第二種繼承

class timethread : public qobject

現在qt官方並不是很推薦繼承qthread來實現多執行緒方法,而是極力推崇繼承qobject的方法來實現,當然用哪個方法實現要視情況而定,別弄錯了就行,估計qt如此推崇繼承qobject的方法可能是qthread太容易用錯的原因。

qobject是qt框架的基本類,但凡涉及到訊號槽有關的類都是繼承於qobject。qobject是乙個功能異常強大的類,它提供了qt關鍵技術訊號和槽的支援以及事件系統的支援,同時它提供了執行緒操作的介面,也就是qobject是可以選擇不同的執行緒裡執行的。

用qobject來實現多執行緒有個非常好的優點,就是預設就支援事件迴圈(qt的許多非gui類也需要事件迴圈支援,如qtimer、qtcpsocket),qthread要支援事件迴圈需要在qthread::run()中呼叫qthread::exec()來提供對訊息迴圈的支援,否則那些需要事件迴圈支援的類都不能正常傳送訊號,因此如果要使用訊號和槽,那就直接使用qobject來實現多執行緒。

1/寫乙個繼承qobject的類,對需要進行複雜耗時邏輯的入口函式宣告為槽函式

2/此類在舊執行緒new出來,不能給它設定任何父物件

3/同時宣告乙個qthread物件,在官方例子裡,qthread並沒有new出來,這樣在析構時

就需要呼叫qthread::wait(),如果是堆分配的話,可以通過deletelater來讓執行緒自殺

5/把執行緒的finished訊號和object的deletelater槽連線,這個訊號槽必須連線,否則會記憶體洩漏

6/正常連線其他訊號和槽(在連線訊號槽之前呼叫movetothread,不需要處理connect

的第五個引數,否則就顯示宣告用qt::queuedconnection來連線)

7/初始化完後呼叫'qthread::start()來啟動執行緒

8/在邏輯結束後,呼叫qthread::quit退出執行緒的事件迴圈

本次需求因為要實現客戶端功能,因此不用宣告乙個伺服器物件,邏輯相對簡單。

smutcpsocket = new qtcpsocket(this);

connect(this->smutcpsocket,signal(connected()),this,slot(on_conn()));

connect(this->smutcpsocket,signal(error(qabstractsocket::socketerror)),this,slot(showerror(qabstractsocket::socketerror)));

捕捉連線成功和連線失敗的訊號。

new的時候用this指標作為引數讓socket物件週期和父類一致(父死子死),確保不會記憶體洩漏,當然保險還是要在析構函式裡delete掉。

connect(this->m_timer, signal(timeout()),this,slot(trytoconnect()));

m_timer->setinterval(9000);

m_timer->start();

void smuthread::trytoconnect()

debug列印是否有執行,個人覺得比斷點好用,看自己習慣。

定時器9秒會觸發一次connecttohost邏輯,那怎麼判斷是否鏈結成功呢?

答案就是

signal(connected())
因為qt封裝的很好,所以直接用訊號捕捉就行了。

void smuthread::on_conn()

在父視窗mainwindow中:

m_smuthread =

new qthread();

m_smu =

new smuthread();

connect(m_smu,signal(sendstring(qstring)),this,slot(auxiliary_information(qstring)));

m_smu->movetothread(m_smuthread);

m_smuthread->start();

發射出來的訊號會觸發auxiliary_information(qstring)函式,然後

void mainwindow::auxiliary_information(qstring str)

字串會顯示在label中

TCP通訊(客戶端)

修改自網路 include include include pragma comment lib,ws2 32.lib int client void unsigned short port int main int argc,char argv int client void if isockcl...

QT學習 Tcp客戶端通訊(本地回環)

1.linux下tcp通訊 2.qt下tcp通訊 1 tcp框架 簡圖 下面的文字框是寫入文字,上面的是顯示傳送後接收到的資訊。這裡傳送的訊息並不會立刻顯示到介面上,而是要通過 readyread 的函式讀取,即是做接受處理。然後才會顯示傳送的內容。3.如下 ui介面直接拖控制項實現 1 第一部分 ...

TCP通訊,多客戶端通訊(客戶端 服務端)

客戶端和伺服器間的交流,客戶端傳送資訊,伺服器接收到,並返回資訊 長連線建立socket連線服務端 指定ip位址,埠號 通過ip位址找對應的伺服器 呼叫socket的getinputstream 和getoutputstream 方法獲取和服務端相連的io流 輸入流可以讀取服務端輸出流寫出的資料 輸...