WinSock編程的多線程式控制制 |
|
conundrum
尊榮會員 發表:893 回覆:1272 積分:643 註冊:2004-01-06 發送簡訊給我 |
http://geocom.hhcc.net.cn/magz/wk0202/7.htm WinSock編程的多線程式控制制
趙躍龍 張 兵
(中南大學電腦系,湖南長沙 410083)
【摘要】本文通過對WinSock的分析,在Delphi下進行了客戶段和伺服器端的多線程式控制制,以提高在網路上的資料傳輸性能!
【關鍵字】Winsock, Thread
1引言
Windows Sockets規範以U.C. Berkeley大學BSD UNIX中流行的Socket介面為範例定義了一套Microsoft Windows下網路編程介面。它不僅包含了人們所熟悉的Berkeley Socket風格的庫函數;也包含了一組針對Windows的擴展庫函數,以使程式師能充分地利用Windows消息驅動機制進行編程。
Windows Sockets 規範本意在於提供給應用程式開發者一套簡單的API,並讓各家網路軟體供應商共同遵守。此外,在一個特定版本Windows的基礎上,Windows Sockets 也定義了一個二進位介面(ABI),以此來保證應用Windows Sockets API 的應用程式能夠在任何網路軟體供應商的符合Windows Sockets協議的實現上工作。因此這份規範定義了應用程式開發者能夠使用,並且網路軟體供應商能夠實現的一套庫函數調用和相關語義。我們可以使用WinSock在Internet上傳輸資料和交換資訊,而且可以不需要關心網路連接的細節,因而很受網路編程程式師的歡迎。
2 Delphi中Socket的操作方式
Delphi分別使用TClientSocket元件和TServerSocket元件來操縱用戶端 Socket和伺服器段Socket的連接和通信。根據連接發起的方式以及本地 Socket要連接的目標,Socket之間的連接可以分為:用戶端連接、監聽連接以及伺服器端連接。
(1)所謂用戶端連接,是指由用戶端的 Socket提出連接請求,要連接的目標是伺服器端的Socket。為此,用戶端的Socket首先要描述它要連接的伺服器端Socket,主要是伺服器端Socket的位址和埠號,然後再定位所要連接的伺服器端Socket。找到以後,就向伺服器端Socket請求連接。此時,伺服器端的Socket未必正好處於準備好狀態。不過,伺服器端Socket會自動維護一個客戶請求佇列,通過這個佇列的優先順序,會在適當的時候通過請求回應的方式向用戶端Socket發出“允許連接”(Accept)的信號,這樣便在用戶端和伺服器端通過Sockets建立了連接!
(2)所謂監聽連接,是指伺服器端Socket並不定位具體的用戶端Socket,而是處於等待連接狀態,當伺服器端 Socket監聽到或者接收到用戶端Socket的連接請求的時候,它就回應用戶端Socket的請求建立一個新的Socket控制碼並與用戶端連接,而伺服器端Socket繼續處於監聽狀態,這樣可以與多個用戶端同時建立連接。
(3)所謂伺服器端連接,是指當伺服器端Socket接收到用戶端Socket的連接請求後,就把伺服器端Socket的描述發送給用戶端。一旦用戶端確認了此描述,就建立了連接!
3 線程式控制制的提出
一旦伺服器與用戶端建立了連接之後,就可以通過 Internet 傳輸資料和檔。但是在WinSock中存在兩種傳輸模式“阻塞”和“非阻塞”的概念。
一般都採用非阻塞方式。在用戶端,如果把 ClientType特性設置為ctNonBlocking,表示採用非阻塞方式進行連接。當伺服器端 Socket試圖進行讀/寫操作的時候,用戶端 Socket就會得到通知,即OnRead或者OnWrite事件。
對於伺服器端Socket來說,如果把ServerType特性設置為 StNonBlocking,表示採取非阻塞方式進行連接。當用戶端 Socket試圖進行讀/寫的時候,伺服器端Socket就會得到通知,即OnClientRead或者OnClientWrite事件。
與非阻塞方式不同的是,在阻塞方式下沒有諸如OnRead或者OnWrite等非同步事件。Socket必須主動去讀或者寫資料。在讀寫操作完成之前,其他代碼都無法執行,成為了純粹的獨佔使用方式,整個應用程式將處於等待狀態,大大降低應用程式的性能。
對於用戶端Socket來說,如果把 ClientType特性設置為ctBlocking,表示採取阻塞方式進行連接,為了盡可能的減少阻塞方式的負面影響,可以把所有涉及到讀寫的操作放在一個單獨的線程中,這樣可以使其他的線程可以繼續得到執行。
對於伺服器端 Socket來說,如果把ServerType設置為stThreadBlocking,表示採取阻塞方式進行連接。Delphi 中將為每一個阻塞方式的連接自動分配一個新的線程,這樣即使一個客戶正在進行讀寫操作,其他的客戶也不必等待。
4 在用戶端使用多線程技術
在阻塞模式下,為了盡可能的減少阻塞方式的副作用,可以把所有的涉及到讀寫操作放在一個單獨的線程種。為此,需要創建一個新的線程物件,然後重載它的Execute方法,線上程代碼中,我們通過TWinSockStream物件來進行讀寫操作。
Procedure TClientThread.Execute;
Var sStream: TWinSockStream;
sBuffer: string;
Begin
//建一個TWinSocketStream物件實例,設置連接超時
SSteam: = TWinSockStream.Create (ClientSocket.Socket, 60000);
Try //獲取和操作命令,直到連接斷開或者線程終止
While (not Terminate) and (ClientSocket.Active) do
begin
try
GetNextRequest (sBuffer);
//將請求寫回到Server
sStream.Write (sBuffer, Length (sBuffer) 1);
…
Except
if not(Except Object is EAbort) then
//處理一些自定義的異常情況
Synchronize(HandleThreadException);
end;
end;
finally
sStream.Free;
end;
End;
5 在伺服器端使用多線程技術
在伺服器端,Delphi將自動為每一個阻塞方式的連接分配一個新的線程,並通過TServerClientThread來操縱每一個線程。所以不能通過物件庫中的嚮導來創建線程物件,只能手工建立一個TServerClientThread的派生類,然後重載ClientExcute方法。Procedure TServerThread.ClientExcute;
Var sStream:TWinSocketStream;
sBuffer:array[0..9] of char
Begin
//獲取和操作命令,直到連接斷開或者線程終止
While (not Terminate) and (ClientSocket.Active) do
Begin
Try
sStream:= TWinSocketStream.Create(ClientSocket.Socket,60000);
try //填充SBuffer陣列
FillChar(sBuffer,10,0);
//延遲時間60秒
If sStream.WaitForData(60000) then
Begin
If sStream.Read(sBuffer,10)=0 then
ClientSocket.Close;
……
End
Else ClientSocket.Close;
except
HandleException;
end;
Finally
sStream.Free;
end;
end;
End;
總結:通過用戶端和伺服器端的多線程式控制制,當我們需要對大信息量的資料處理的時候,尤為方便,而且能夠很大程度上提高網路資源的利用率。目前我們正在研究通過線程式控制制來對資料庫的查詢進行優化處理以及資料發送問題!
參考資料:
[1] Steve Teixeira等著,任旭鈞等譯,Delphi 5開發人員指南,機械工業出版社。北京:2000.7
[2] Martin Hall等,“Windows Sockets-An Open Interface for Network Programming under Microsoft Windows”,Document, 1993年
(收稿日期:2002.04.21 Email: Paper.2000@163.com}
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |