WinSock編程的多線程控制
版權全部 codesky.net 2003-2005
發表時間:2004-11-16關鍵字:Sockets,多線程
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; |
總結:經過客戶端和服務器端的多線程控制,當咱們須要對大信息量的數據處理的時候,尤其方便,並且可以很大程度上提升網絡資源的利用率。目前咱們正在研究經過線程控制來對數據庫的查詢進行優化處理以及數據發送問題!