構建多執行緒的伺服器

2021-06-23 00:03:29 字數 4335 閱讀 3799

簡單的來說,就是同時有多個執行緒一起執行,而不同的執行緒可以執行不同的操作。舉個例子,乙個影象處理工具,可以用滑鼠一邊移**像,一邊用快捷鍵縮放影象,此時,移**像、縮放影象就是不同的執行緒來處理的,如果不支援多執行緒而是單執行緒的,那麼只能挨個操作了。

而對於伺服器來說,多執行緒的這個特性太有用了,因為多執行緒使得伺服器可能同時響應多個客戶端的請求,所以現在伺服器大多採用多執行緒,所以才會造成我開始的誤解。

不管是多執行緒,還是伺服器,qt中已經封裝好了特定的類,所以使用起來也很方便。

下面建立

乙個支援多執行緒、tcp的伺服器。

首先建立乙個伺服器。新建乙個類(server)繼承qt中的qtcpserver類即可。伺服器的職責是監聽埠。當監聽到有客戶端試圖與伺服器建立連線的時候,分配socket

與客戶端連線,再進行資料通訊

。qtcpserver的listen()方法執行監聽過程,可以指定監聽的位址和埠。若給定了qhostaddress型別的監聽位址,則監聽該位址,否則,監聽所有位址;若給定了quint16型別的監聽埠,則監聽該埠,否則,隨機選定乙個監聽埠。

view plain

copy to clipboard

print

? server * server =newserver;   

if(!server->listen(host,port))  

qtcpserver有乙個虛函式incomingconnection(int socketdescriptor),伺服器每當監聽到乙個客戶端試圖建立連線的時候,會自動呼叫這個函式,因此,處理這個請求的過程就可以在這個函式中電影,即在子類server的定義階段,重新定義incomingconnection()這個函式。對於乙個多執行緒的伺服器,每當客戶端試圖連線的時候,伺服器應該啟動乙個執行緒,負責對這個客戶端進行服務,所以,incomingconnection()這個函式所要做的就是建立乙個執行緒,而所建立的執行緒的作用就是對客戶端進行服務,而這其中建立socket連線是基礎。伺服器在監聽到客戶端試圖建立socket連線時,會為此socket分配乙個唯一的標識socketdescriptor,這個標識將在伺服器端建立socket連線時使用,所以應提供給每乙個執行緒。

在qt中使用多執行緒,建立乙個類(thread)繼承qthread類即可。qthread類也有乙個虛函式,這個函式是run(),執行緒建立並啟動(qthread::start())後,就會執行這裡面的**,因此,執行緒的邏輯過程就應該在run()裡面定義。伺服器的執行緒要根據socketdescriptor標識的socket建立連線,然後進行資料通訊,所以要將socketdescriptor傳入到thread中,前面說過,執行緒是在incomingconnection()裡面建立,用建構函式將socketdescriptor傳入thread類,再用socketdescriptor建立socket連線。

定義incomingconnection()

view plain

copy to clipboard

print

? voidincomingconnection(intsocketdescriptor)  

定義run()

view plain

copy to clipboard

print

? voidrun()  

自此,乙個簡單的多執行緒伺服器建立完畢。

寫的不好,望請指教。

*************************===

qt4中socket通訊

最近的軟體工程

課程設計讓我重新開始使用qt,上次資料結構的課程設計

也是用qt,雖然是做出來了,但是現在想想,那個時候對qt的理解,或者說得更廣一點,對oo的理解,簡直太差勁了,當然,人的知識是進步的,所以現在有這樣的感受是很正常的。雖然整體的開發工作還沒有完全結束,但是已經有了很多心得體會,所以特來記錄分享一下。

我們的系統採用的是c/s結構,所以客戶端與伺服器

通訊是最關鍵,不幸的是,雖然我們沒有用過qt的socket

類,我們也沒有估計好通訊

的難度,等到意識到第一次使用的困難時,已經是第5天了,始終沒有進展,我臨危受命。現在是第6天,剛剛把通訊模組封裝好,算是對這兩天的突擊

的乙個回報。

我們遇到的問題socket已經建立

,並且傳送端已經將訊息傳送,但是接收端始終收不到訊息。(我用的socket型別是tcp,也就是qtcpsocket類)

傳送端(傳送端一直不存在問題)**如下:

view plain

copy to clipboard

print

? ... // 建立連線,客戶端和伺服器端有區別,在此省略

qbytearray block;   

qdatastream out(&block,qiodevice::writeonly);  // 寫資訊至block中,用到qdatastream類

socket.write(block);// 資訊寫完畢,寫入socket,由socket傳送

socket.disconnectformhost();   

socket.waitfordisconnected();  

有問題的接收端**如下:

view plain

copy to clipboard

print

? ... // 建立連線

qdatastream in(&socket);// 接收socket中的資料流

... // 從資料流 in 中讀資料

以上是最原始的接收和傳送端工作過程,除錯過程中,分別講兩端的socket的狀態列印出來,結果是傳送端為a connection is established. 而接收端為the socket has started establishing a connection. 也就是說傳送端正確的建立了連線,並將資料寫入,而接收端只是正在建立連線,而並沒有建立好,所以是根本不會受到資料的。所以先要確保接收端的連線建立好。waitforconnected()方法就可以解決這個問題,它將一直等待直到連線已經建立。

改進後的接收端**:

view plain

copy to clipboard

print

? ... // 建立連線

socket.waitforconnected(5000) // 5000表示等待的時間,預設引數為3000,單位是百萬分之一秒 

qdatastream in(&socket);// 接收socket中的資料流

... // 從資料流 in 中讀資料

此時,接收端輸出的socket狀態為a connection is established,連線成功建立。

但是還是收不到資訊,參考了一下別人的程式,再比對一下參考手冊,原來qtcpsocket的爺爺類(其實是父類qabstractsocket的父類)qiodevice有乙個readyread的訊號(signal),當資訊準備好並可以讀的時候,這個訊號就將發出,也就是說,只有當這個訊號發出的時候,才可以讀訊息。所以要把讀訊息的動作read作為乙個槽(slot),並將其與readyread訊號連線。

view plain

copy to clipboard

print

? connect(&socket,signal(readyread()),this,slot(read()));  

但是直接觸發socket訊號,而不用圖形介面的動作來觸發乙個動作並由這個動作來觸發socket訊號一直也觸發不了read這個動作。但是我要封裝成乙個介面類提供給上層使用,用圖形介面自然是不現實的,於是翻閱了手冊,發現了乙個qabstractsocket類的乙個方法——waitforreadyread(),這個方法將一直等待到資料可以讀時結束,此時就可以讀資料了。方法也很簡單:

view plain

copy to clipboard

print

? ... // 建立連線

socket.waitforconnected(5000) // 5000表示等待的時間,預設引數為3000,單位是百萬分之一秒

if(!socket.waitforreadyread(3000))

qdatastream in(&socket);// 接收socket中的資料流

... // 從資料流 in 中讀資料

這樣,資料成功讀取出來,實現資料的通訊。

單向的資料傳輸問題解決了,然後再利用單向的資料通訊組裝成雙向的資料通訊,這過程中也會遇到不少問題,將在另一篇日誌介紹。

********************====

多執行緒併發構建基礎伺服器

threading的多執行緒併發 對比多程序併發 消耗資源較少 執行緒應該更注意共享資源的操作 在python中應該注意gil問題,網路延遲較高,執行緒併發也是一種可行的方法 實現步驟 1.建立套接字,繫結監聽 2.接收客戶端請求,建立新的執行緒 3.主線程繼續接收其他客戶端連線 4.分支執行緒啟動...

多執行緒伺服器

posix執行緒庫 a 與執行緒有關的函式都構成了乙個完整的系列,絕大多數函式的名字都是以 pthread 打頭的。b 要使用這些庫函式,要引入標頭檔案。c 鏈結這些執行緒庫函式時要使用編譯命令的 lpthread 選項。int pthread create pthread t thread,con...

多執行緒的伺服器

許多實際應用要求伺服器具有同時為多個客戶提供服務的能力。用多個執行緒來同時為多個客戶提供服務,這是提高伺服器的併發效能的最常用的手段。主要有3種方式來實現 第一種方式的不足之處 執行緒池為執行緒生命週期開銷問題和系統資源不足問題提供了解決方案。執行緒池中預先建立了一些工作執行緒,它們不斷從工作佇列中...