


版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、Indy10InstallAll packages are followed by X0 (Where X is your Delphi verison).1. Download source from the Development Snapshot.Delphi / BCB Installation1. Open and compile in the following order:2.1. IndySystem (in LibSystem)2. IndyCore (in LibCore)3. IndyProtocols (in LibProtocols)4. IndySuperCore
2、(in LibSuperCore)If you are not using SuperCore, then you do not need to compile this package.3. Now open and click install in the following order4.5.1. dclIndyCore (in LibCore)2. dclIndyProtocols (in LibProtocols)3. dclSuperCore (in LibSuperCore)Only install this if you have compiled SuperCore.利用 D
3、elphi 編寫 Socket 通信程序2004-08-24 人氣: 5925 出處: csdn 作者 : dudunono 原作 一、Delphi 與 Socket計(jì)算機(jī)網(wǎng)絡(luò)是由一系列網(wǎng)絡(luò)通信協(xié)議組成的,其中的核心協(xié)議是傳輸層的TCP/IP和UDP協(xié)議。TCP是面向連接的,通信雙方保持一條通路,好比目前的電話線,使用telnet登陸B(tài)BS,用的就是TCP協(xié)議;UDP是無連接的,通信雙方都不保持對(duì)方的狀態(tài),瀏覽器訪問Internet時(shí)使用的HTTP協(xié)議就是基于UDP協(xié)議的。TCP和UDP協(xié)議都非常復(fù)雜,尤其是 TCP協(xié)議,為了保證網(wǎng)絡(luò)傳輸?shù)恼_性和有效性,必須進(jìn)行一系列復(fù)雜的糾錯(cuò)和排序等處理。
4、Socket是建立在傳輸層協(xié)議(主要是TCP和UDP上的一種套接字規(guī)范,最初是由美國加州Berkley大學(xué)提出,它定義兩臺(tái)計(jì)算機(jī)間進(jìn)行通信的規(guī)范(也是一種編程規(guī)范) ,如果說兩臺(tái)計(jì)算機(jī)是利用一個(gè)“通道“進(jìn)行通信,那么這個(gè)“通道“的兩端就是兩個(gè)套接字。套接字屏蔽了底層通信軟件和具體操作系統(tǒng)的差異,使得任何兩臺(tái)安裝了TCP協(xié)議軟件和實(shí)現(xiàn)了套接字規(guī)范的計(jì)算機(jī)之間的通信成為可能。微軟的Windows Socket規(guī)范(簡稱winsock)對(duì)Berkley的套接字規(guī)范進(jìn)行了擴(kuò)展,利用標(biāo)準(zhǔn)的Socket的方法,可以同任何平臺(tái)上的 Socket 進(jìn)行通信;利用其擴(kuò)展,可以更有效地實(shí)現(xiàn)在Windows平臺(tái)上計(jì)
5、算機(jī)間的通信。在Delphi中,其底層的 Socket也應(yīng)該是 Windows的Socket。Socket減輕了編寫計(jì)算機(jī)間通信軟件的難度,但總的說來還是相當(dāng)復(fù)雜的(這一點(diǎn)在后面具體會(huì)講到); Inprise 在 Delphi 中對(duì) Windows Socket 進(jìn)行了有效的封裝,使得用戶可以很方便地編寫網(wǎng)絡(luò)通信程 序。下面我們實(shí)例解讀在 Delphi 中如何利用 Socket 編寫通信程序。二、利用 Delphi 編寫 Socket 通信程序。下面是一個(gè)簡單的 Socket 通信程序,其中客戶機(jī)和服務(wù)機(jī)是同一個(gè)程序,當(dāng)客戶機(jī)(服務(wù)器)在一個(gè)memo1中輸入一段文字然后敲入回車,該段文字就可以
6、顯示在服務(wù)器(客戶機(jī))的memo2中,反之亦成立。具體步驟如下:1、新建一個(gè)form,任意命名,不妨設(shè)之為 chatForm ;放上一個(gè) MainMenu(在Standard 欄中),建立 ListenItem 、 ConnectItem 、 Disconnect 和 Exit 菜單項(xiàng);在從 Internet 欄中選擇TServerSocket 、TClientSocket 添加到 chatForm 中,其中把 TClientSocket 的名字設(shè)為 ClientSocket, port 設(shè)為 1025,默認(rèn)的 active 為 false ;把 TServerSocket 的名字設(shè)為 Ser
7、verSocket ,port設(shè)為1025,默認(rèn)的active 為false,其他的不變;再放入兩個(gè)memo 個(gè)命名為 memo1另外一個(gè)命名為memo2其中把memo2的 color設(shè)置為灰色,因?yàn)橹饕脕盹@示對(duì)方的輸入。下面我們一邊編寫代碼一邊解釋原因2、雙擊Listemltem。寫入如下代碼:procedure TChatForm.ListenItemClick(Sender: TObject);beginListenltem.Checked := not Listenltem.Checked;if Listenltem.Checked thenbeginClientSocket.Act
8、ive := False;ServerSocket.Active := True;endelsebeginif ServerSocket.Active thenServerSocket.Active := False;end;end;該程序段的說明如下: 當(dāng)用戶選擇 Listemltem 時(shí),該 Listenltem 取反,如果選中的話, 說明處于 Listen 狀態(tài),讀者要了解的是: listen 是 Socket 作為 Server 時(shí)一個(gè)專有的方法,如果處于listen, 則 ServerSocket 設(shè)置為活動(dòng)狀態(tài);否則,取消 listen ,則關(guān)閉 ServerSocket 。實(shí)際上
9、,只有用戶 一開始選擇該菜單項(xiàng),表明該程序用作 Server 。反之,如果用戶選擇 Connectltem ,則必然作為 Client 使用。3、雙擊 Connectitem,敲入以下代碼。procedure TChatForm.ConnectltemClick(Sender: TObject);beginif ClientSocket.Active then ClientSocket.Active := False;if lnputQuery('Computer to connect to', 'Address Name:', Server) thenif L
10、ength(Server) > 0 thenwith ClientSocket dobeginHost := Server;Active := True;Listenltem.Checked := False;end;end;這段程序的主要功能就是當(dāng)用戶選擇 Connectltem 菜單項(xiàng)時(shí), 設(shè)置應(yīng)用程序?yàn)榭蛻魴C(jī), 彈出 input 框, 讓用戶輸入服務(wù)器的地址。這也就是我們不一開始固定 ClientSocket 的 host 的原因,這樣用戶可以動(dòng)態(tài)地連接不同的服務(wù)器。 讀者需要了解的是主機(jī)地址只是 Socket 作為客戶機(jī)時(shí)具有的一個(gè) 屬性, Socket 作為服務(wù)器時(shí)“一般“不用
11、地址,因?yàn)樗緳C(jī)綁定。4、在 memol的keydown方法中寫入如下代碼:procedure TChatForm.Memo1KeyDown(Sender: TObject; var Key: Word;Shift: TShiftState);beginif Key = VK_Return thenif IsServer thenServerSocket.Socket.Connections0.SendText(Memo1.LinesMemo1.Lines.Count - 1)elseClientSocket.Socket.SendText(Memo1.LinesMemo1.Lines.Co
12、unt - 1); end;該段代碼的作用很明顯,就是開始發(fā)消息了。其中如果是 Server 的話,它只向第一個(gè)客戶機(jī)發(fā)消息, 由于一個(gè)服務(wù)器可以連接多個(gè)客戶機(jī),而同客戶機(jī)的每一個(gè)連接都由一個(gè) Socket 來維持,因此 ServerSocket.Socket.Connnections 數(shù)組中存儲(chǔ)的就是同 Client 維持連接的 Socket 。在標(biāo)準(zhǔn) Socket 中,服務(wù)器方的 Socket 通過 accept() 方法的返回值獲取維持同客戶機(jī)連接的Socket, 而發(fā)送、接受消息的方法分別為 send(sendto) 和 recv(recvfrom), Delphi 對(duì)此進(jìn)行了封裝。5
13、、其余代碼的簡要介紹。procedure TChatForm.ServerSocketAccept(Sender: TObject;Socket: TCustomWinSocket);beginIsServer := True;end;ServerSocket 的 Accept 方法,當(dāng)客戶機(jī)第一次連接時(shí)完成, 通過其參數(shù)可以認(rèn)為, 它是在標(biāo)準(zhǔn)的 accept 方法后執(zhí)行的,因?yàn)橛?TCustomWinSocket 這個(gè)參數(shù)類型,它應(yīng)該是標(biāo)準(zhǔn) Server 方Socket 的返回值。procedure TChatForm.ClientSocketRead(Sender: TObject;Soc
14、ket: TCustomWinSocket);beginMemo2.Lines.Add(Socket.ReceiveText);end;procedure TChatForm.ServerSocketClientRead(Sender: TObject;Socket: TCustomWinSocket);beginMemo2.Lines.Add(Socket.ReceiveText); end;這兩段代碼分別是服務(wù)器方和客戶機(jī)方在收到對(duì)方的消息時(shí),由Delphi觸發(fā)的,作用是在memo沖顯示收到的消息。其中, ClientSocketRead 中的 Socket 實(shí)際上就是 Socket 本身
15、,而在ServerSocketClientRead 中的 Socket 實(shí)際上是 ServerSocket.Socket.Connection 中的某個(gè) Socket 。不 過在 Delphi 中,對(duì)服務(wù)器方的 Socket 進(jìn)行了有效的封裝。procedure TChatForm.ServerSocketClientConnect(Sender: TObject;Socket: TCustomWinSocket);beginMemo2.Lines.Clear;end;procedure TChatForm.ClientSocketDisconnect(Sender: TObject;Sock
16、et: TCustomWinSocket);beginListenItemClick(nil);end;這兩段比較簡單。其中 ServerSocketClientConnect 在 ServerSocket 收到一個(gè)新的連接時(shí)觸發(fā)。而 ClientSocketDisconnect 在 ClientSocket 發(fā)出 Disconncet 時(shí)觸發(fā)。procedure TChatForm.Exit1Click(Sender: TObject);beginServerSocket.Close;ClientSocket.Close;Close;end;procedure TChatForm.Disco
17、nnect1Click(Sender: TObject);beginClientSocket.Active := False;ServerSocket.Active := True;end;第一段為關(guān)閉應(yīng)用程序。在標(biāo)準(zhǔn) Socket 中,每個(gè) Socket 在關(guān)閉時(shí),必須調(diào)用 closesocket() 方法, 否則系統(tǒng)不會(huì)釋放資源。而在 ServerSockt.Close 和 ClientSocket.Close 中,系統(tǒng)內(nèi)部肯定調(diào)用了 closesocket ()方法。三、標(biāo)準(zhǔn) Socket 與 Delphi 中的 Socket 。標(biāo)準(zhǔn)的 Socket 的應(yīng)用程序框架如下:Server 方
18、: Socket() 新建一個(gè) Socket Bind()同服務(wù)器地址邦定 Listen() Accept() block wait read() 接受消息,在 windows 平臺(tái)中,方法為 send(TCP), 或者是sendto(UDP) 處理服務(wù)請(qǐng)求 Write() 發(fā)送消息,在 windows 平臺(tái)中,方法為 send(TCP), 或者為 sendto(UDP) 。Client 方相對(duì)簡單: Socket() Connect() 通過一定的 port 連接特定的服務(wù)器,這是與服務(wù)器建立連 接 Write() Read() 。Socket可以是基于 TCP的,也可以是基于 UDP,同時(shí)
19、Socket甚至建立在其他的協(xié)議,比如IPX/SPX,DECNet等。在新建一個(gè)Socket時(shí),可以指定新建何類 Socket。Bind()用來同服務(wù)器的地址邦定,如果一個(gè)主機(jī)只有一個(gè) IP 地址,實(shí)際上邦定的作用就相對(duì)多余了。 Listen() 開始監(jiān)聽網(wǎng)絡(luò), Accept() 用于接受連接,其返回值是保持同客戶機(jī)聯(lián)系的 Socket。在Delphi中,對(duì)于 Windows中的Socket進(jìn)行了有效的封裝。在 Delphi中,按其繼承關(guān)系,可以分層 兩類:一、TComponentTAbstractSocketTCustomSocketTCustomServerSocketTServerSoc
20、ketTComponent TAbstractSocket TCustomSocket TClientSocket二、直接從 TObject 繼承過來 :TObject TCustomWinSocket TServerWinSocketTObject TCustomWinSocket TClientWinSocketTObject TCustomWinSocket TServerClientWinSocket可以看出第一類建立在 TCustomSocket 基礎(chǔ)上, 第二類建立在 TCustomWinSocket 的基礎(chǔ)上。 第一類建 立在TComponet的基礎(chǔ)上,第二類直接構(gòu)建在TObje
21、ct基礎(chǔ)上。因此如果用戶非常熟悉Socket 并且想要編寫控制臺(tái)程序時(shí),可以使用 TCustomWinScoket 類。同 uses 中可以看出,它們都在 ScktComp.pas 中實(shí)現(xiàn),而在 schtComp.pas 中,則包含了 winsock.pas 文件,如果繼續(xù)深入 winsock 文件,在其中可以發(fā)現(xiàn)所有的 Windows Socket 的基本方法。實(shí)際上, 如果你了解了標(biāo)準(zhǔn) Socket 的應(yīng)用程序框架, 對(duì)于使用 Delphi 編寫 Socket 應(yīng)用程序也就得心 應(yīng)手了;這不是說你必須了解復(fù)雜的Socket 中的標(biāo)準(zhǔn)函數(shù),也沒有必要,因?yàn)?Delphi 已經(jīng)為你做了很好的封
22、裝了,這也正是Delphi 的強(qiáng)勢所在,你只要了解那么一點(diǎn)點(diǎn)的基本框架。這是我對(duì) Delphi 中的 Socket 應(yīng)用的理解, 不足之處希望大家指正。 同時(shí)也樂于為大家解答 Delphi 中 有關(guān) Socket 的問題。用 Indy 組件開發(fā) Socket 應(yīng)用程序創(chuàng)建時(shí)間: 2004-3-16 文章屬性:轉(zhuǎn)載 文章提交:絕對(duì)零度今日瀏覽: 23總共次數(shù): 648文章作者:虛度文章出處: yesky筆者在前一段的工作中, 需要開發(fā)一套簡單的網(wǎng)絡(luò)數(shù)據(jù)傳輸程序。由于平時(shí)常用 Delphi 做點(diǎn)開發(fā), 故 此次也不例外。 Delphi 7 中帶有兩套 TCP Socket 組件: Indy Soc
23、ket 組件( IdTCPClient 和 IdTCPServer )和 Delphi 原生的 TCPSocket 組件( ClientSocket 和 ServerSocket )。但 是, Borland 已宣稱 ClientSocket 和 ServerSocket 組件即將被廢棄,建議用相應(yīng)的 Indy組件來代替。因此,筆者使用了 Indy 。本文在對(duì) Indy 進(jìn)行簡要介紹的基礎(chǔ)上, 創(chuàng)建了一組簡單的 TCPSocket 數(shù)據(jù)傳輸應(yīng)用來演示了 Indy 的使用方法。開放源代碼的 Internet 組件集 Internet Direct (Indy ) Internet Direct
24、(Indy )是一組開放源 代碼的 Internet 組件,涵蓋了幾乎所有流行的 Internet 協(xié)議。 Indy 用 Delphi 編寫,被包含在Delphi 6,Kylix 1和C+ Builder 6及以上各個(gè)版本的 Borland開發(fā)環(huán)境中。Indy曾經(jīng)叫做 WinShoes (雙關(guān)于 WinSockWindows的Socket庫),是由Chad乙Hower領(lǐng)導(dǎo)的一群開發(fā)者構(gòu)建的,可以從 Indy 的站 上找到更多的信息并下載其新版本。到筆者撰寫本文時(shí) 為止, Indy 的最新穩(wěn)定版是 9.0.14 , Indy 10 也進(jìn)入了 Beta 測試階段。Delphi 7 中所帶的是 In
25、dy 9 。在其的組件面板上,一共安裝有 100多個(gè) Indy 組件。使用這些組件你 可以開發(fā)基于各種協(xié)議的 TCP客戶和服務(wù)器應(yīng)用程序,并處理相關(guān)的編碼和安全問題。你可以通過前綴 Id 來識(shí)別 Indy 組件。Indy 是阻塞式( Blocking )的當(dāng)你使用 Winsock 開發(fā)網(wǎng)絡(luò)應(yīng)用程序時(shí),從 Socket 中讀取數(shù)據(jù)或者向 Socket 寫入數(shù)據(jù)都是異步發(fā)生 的,這樣就不會(huì)阻斷程序中其它代碼的執(zhí)行。在收到數(shù)據(jù)時(shí),Winsock 會(huì)向應(yīng)用程序發(fā)送相應(yīng)的消息。這種訪問方式被稱作非阻塞式連接,它要求你對(duì)事件作出響應(yīng),設(shè)置狀態(tài)機(jī),并通常還需要 一個(gè)等待循環(huán)。與通常的 Winsock 編程方
26、法不同的是, Indy 使用了阻塞式 Socket 調(diào)用方式。阻塞式訪問更像是文件存取。當(dāng)你讀取數(shù)據(jù),或是寫入數(shù)據(jù)時(shí),讀取和寫入函數(shù)將一直等到相應(yīng)的操作完成后才返回。比如說,發(fā)起網(wǎng)絡(luò)連接只需調(diào)用 Connect 方法并等待它返回,如果該方法執(zhí)行成功,在結(jié)束時(shí)就 直接返回,如果未能成功執(zhí)行,則會(huì)拋出相應(yīng)的異常。同文件訪問不同的是,Socket調(diào)用可能會(huì)需要更長的時(shí)間, 因?yàn)橐x寫的數(shù)據(jù)可能不會(huì)立即就能準(zhǔn)備好 (在很大程度上依賴于網(wǎng)絡(luò)帶寬) 。阻塞式 Socket 并非惡魔( Evil )長期以來, 阻塞式 Socket 都遭到了毫無理由的攻擊。 其實(shí)阻塞式 Socket 并非如通常所說的那樣可怕
27、。 這還要從 Winsock 的發(fā)展說起。當(dāng) Socket 被從 Unix 移植到 Windows 時(shí),一個(gè)嚴(yán)重的問題立即就出現(xiàn)了。 Unix 支持 fork ,客戶程序和 服務(wù)器都能夠 fork 新的進(jìn)程,并啟動(dòng)這些進(jìn)程,從而能夠很方便地使用阻塞式 Socket 。而 Windows 3.x 既不支持 fork 也不支持多線程,當(dāng)使用阻塞式 Socket 時(shí),用戶界面就會(huì)被“鎖住”而無 法響應(yīng)用戶輸入。為克服 Windows 3.x 的這一缺陷,微軟在 Winsock 中加入了異步擴(kuò)展,以使 Winsock 不會(huì)“鎖住”應(yīng) 用程序的主線程(也是唯一的線程) 。然而,這需要了一種完全不同的編程
28、方式。于是有些人為了掩飾這一弱點(diǎn),就開始強(qiáng)烈地誹謗阻塞式 Socket 。當(dāng) Win32 出現(xiàn)的時(shí)候,它能夠很好地支持線程。但是既成的觀念已經(jīng)很難更改,并且說出去的話也無 法收回,因此對(duì)阻塞式 Socket 的誹謗繼續(xù)存在著。事實(shí)上,阻塞式 Socket 仍然是 Unix 實(shí)現(xiàn) Socket 的唯一方式,并且它工作得很好。阻塞式 Socket 的優(yōu)點(diǎn)歸結(jié)起來,在 Windows 上使用阻塞式 Socket 開發(fā)應(yīng)用程序具有如下優(yōu)點(diǎn):編程簡單阻塞式 Socket 應(yīng)用程序很容易編寫。 所有的用戶代碼都寫在同一個(gè)地方, 并且順序執(zhí)行。 容易向 Unix 移植由于 Unix 也使用阻塞式 Socke
29、t ,編寫可移植的代碼就變得比較容易。 Indy 就是利用 這一點(diǎn)來實(shí)現(xiàn)其多平臺(tái)支持而又單一源代碼的設(shè)計(jì)。很好地利用了線程技術(shù)阻塞式 Socket 是順序執(zhí)行的, 其固有的封裝特性使得它能夠很容易地使用 到線程中。阻塞式 Socket 的缺點(diǎn)事物都具有兩面性, 阻塞式 Socket 也不例外。它的一個(gè)主要的缺點(diǎn)就是使客戶程序的用戶界面 “凍結(jié)” 當(dāng)在程序的主線程中進(jìn)行阻塞式 Socket 調(diào)用時(shí),由于要等待 Socket 調(diào)用完成并返回,這段時(shí)間就不能處理用戶界面消息,使得Update 、Repaint 以及其它消息得不到及時(shí)響應(yīng),從而導(dǎo)致用戶界面被“凍結(jié)” 。使用 TIdAntiFreeze
30、 對(duì)抗“凍結(jié)”Indy 使用一個(gè)特殊的組件 TIdAntiFreeze 來透明地解決客戶程序用戶界面“凍結(jié)”的問題。TIdAntiFreeze 在 Indy 內(nèi)部定時(shí)中斷對(duì)棧的調(diào)用,并在中斷期間調(diào)用Application.ProcessMessages方 法 處 理 消 息 , 而 外 部 的 Indy 調(diào) 用 繼 續(xù) 保 存 阻 塞 狀 態(tài) , 就 好 像TIdAntiFreeze 對(duì)象不存在一樣。你只要在程序中的任意地方添加一個(gè) TIdAntiFreeze 對(duì)象,就能在客戶程序中利用到阻塞式 Socket 的所有優(yōu)點(diǎn)而避開它的一些顯著缺點(diǎn)。Indy 使用了線程技術(shù)阻塞式 Socekt 通常
31、都采用線程技術(shù), Indy 也是如此。從最底層開始, Indy 的設(shè)計(jì)都是線程化的。因此用 Indy 創(chuàng)建服務(wù)器和客戶程序跟在 Unix 下十分相似,并且 Delphi 的快速開發(fā)環(huán)境和Indy 對(duì) WinSock 的良好封裝使得應(yīng)用程序創(chuàng)建更加容易。Indy 服務(wù)器模型一個(gè)典型的 Unix 服務(wù)器有一個(gè)或多個(gè)監(jiān)聽進(jìn)程, 它們不停地監(jiān)聽進(jìn)入的客戶連接請(qǐng)求。 對(duì)于每一個(gè)需 要服務(wù)的客戶,都 fork 一個(gè)新進(jìn)程來處理該客戶的所有事務(wù)。這樣一個(gè)進(jìn)程只處理一個(gè)客戶連接,編程就變得十分容易。Indy 服務(wù)器工作原理同 Unix 服務(wù)器十分類似, 只是 Windows 不像 Unix 那樣支持 fork
32、 ,而是支持線程, 因此 Indy 服務(wù)器為每一個(gè)客戶連接分配一個(gè)線程。圖 1 顯示了 Indy 服務(wù)器的工作原理。 Indy 服務(wù)器組件創(chuàng)建一個(gè)同應(yīng)用程序主線程分離的監(jiān)聽線程來 監(jiān)聽客戶連接請(qǐng)求,對(duì)于接受的每一個(gè)客戶,都創(chuàng)建一個(gè)新的線程來為該客戶提供服務(wù),所有與這一客戶相關(guān)的事務(wù)都由該線程來處理。使用組件 TIdThreadMgrPool , Indy 還支持線程池。上一頁 1 2 3 4 下一頁線程與 Indy 客戶程序Indy 客戶端組件并未使用線程。但是在一些高級(jí)的客戶程序中,程序員可以在自定義的線程中使用Indy 客戶端組件,以使用戶界面更加友好。簡單的 Indy 應(yīng)用示例下面將創(chuàng)建
33、一個(gè)簡單的 TCP客戶程序和一個(gè)簡單的 TCP服務(wù)器來演示Indy的基本使用方法。客戶程序使用TCP協(xié)議同服務(wù)器連接,并向服務(wù)器發(fā)送用戶所輸入數(shù)據(jù)。服務(wù)器支持兩條命令:DATA和QUIT。在DATA命令后跟隨要發(fā)送的數(shù)據(jù),并用空格將命令字DATA和數(shù)據(jù)分隔開表單布局建立一個(gè)項(xiàng)目組,添加一個(gè)客戶程序項(xiàng)目和一個(gè)服務(wù)器項(xiàng)目??蛻舫绦蚝头?wù)器程序的表單布局如同2 和圖 3 所示??蛻舫绦虮韱紊戏胖昧?TIdTCPClient 組件,服務(wù)器程序表單上放置了TIdTCPServer 組件。為防止客戶程序“凍結(jié)” ,還在其表單上放置 TIdAntiFreeze 組件??蛻舫绦蚝头?wù)器程序的表單上都放置有 T
34、ListBox 組件,用來顯示通信記錄??蛻舫绦虼a客戶程序片斷如代碼列表 1 所示。代碼列表 1procedure TFormMain.BtnConnectClick(Sender: TObject);beginIdTCPClient.Host := EdtHost.Text;IdTCPClient.Port := StrToInt(EdtPort.Text);LbLog.Items.Add(' 正在連接 ' + EdtHost.Text + '.');with IdTCPClient dobegintryConnect(5000);tryLbLog.Item
35、s.Add(ReadLn();BtnConnect.Enabled := False;BtnSend.Enabled := True;BtnDisconnect.Enabled := True; exceptLbLog.Items.Add(' 遠(yuǎn)程主機(jī)無響應(yīng)! ');IdTCPClient.Disconnect();end;/end try exceptLbLog.Items.Add(' 無法建立到 ' + EdtHost.Text + '的連接! ');end;/end tryend;/end withend;procedure TFormMa
36、in.BtnSendClick(Sender: TObject); beginLbLog.Items.Add('DATA ' + EdtData.Text);with IdTCPClient dobegintryWriteLn('DATA ' + EdtData.Text);LbLog.Items.Add(ReadLn()exceptLbLog.Items.Add(' 發(fā)送數(shù)據(jù)失??! ');IdTCPClient.Disconnect();LbLog.Items.Add(' 同主機(jī) ' + EdtHost.Text + '
37、 的連接已斷開! ');BtnConnect.Enabled := True;BtnSend.Enabled := False;BtnDisconnect.Enabled := False;end;/end tryend;/end withend;procedure TFormMain.BtnDisconnectClick(Sender: TObject);varReceived: string;beginLbLog.Items.Add('QUIT');tryIdTCPClient.WriteLn('QUIT');finallyIdTCPClient.D
38、isconnect();LbLog.Items.Add(' 同主機(jī) ' + EdtHost.Text + ' 的連接已斷開! ');BtnConnect.Enabled := True;BtnSend.Enabled := False;BtnDisconnect.Enabled := False;end;/end tryend;在“連接”按鈕事件響應(yīng)過程中,首先根據(jù)用戶輸入設(shè)置 IdTCPClient 的主機(jī)和端口,并調(diào)用 IdTCPClient 的 Connect 方法向服務(wù)器發(fā)出連接請(qǐng)求。然后調(diào)用ReadLn 方法讀取服務(wù)器應(yīng)答數(shù) 據(jù)。在“發(fā)送”按鈕事件響應(yīng)
39、過程中,調(diào)用WriteLn方法寫DATA命令,向服務(wù)器發(fā)送數(shù)據(jù)在“斷開”按鈕事件響應(yīng)過程中,向服務(wù)器發(fā)送QUIT命令,并調(diào)用Disconnect方法斷開連接。程序中還包含有通信信息記錄和異常處理的代碼。服務(wù)器程序代碼服務(wù)器程序片斷如代碼列表 2 所示。代碼列表 2procedure TFormMain.BtnStartClick(Sender: TObject); beginIdTCPServer.DefaultPort := StrToInt(EdtPort.Text);IdTCPServer.Active := True;BtnStart.Enabled := False;BtnStop.
40、Enabled := True;LbLog.Items.Add(' 服務(wù)器已成功啟動(dòng)! ');end;procedure TFormMain.BtnStopClick(Sender: TObject); beginIdTCPServer.Active := False;BtnStart.Enabled := True;BtnStop.Enabled := False;LbLog.Items.Add(' 服務(wù)器已成功停止! ');end;procedure TFormMain.IdTCPServerConnect(AThread: TIdPeerThread);
41、beginLbLog.Items.Add(' 來自主機(jī) '+ + ' 的連接請(qǐng)求已被接納! ');AThread.Connection.WriteLn('100:歡迎連接到簡單 TCP服務(wù)器!);end;procedure TFormMain.IdTCPServerExecute(AThread: TIdPeerThread);varsCommand: string;beginwith AThread.Connection dobeginsCommand := ReadLn();FLogEntry := sCommand + ' 來自于主機(jī)
42、39;+ AThread.Connection.Socket.Binding.PeerIP; AThread.Synchronize(AddLogEntry);if AnsiStartsText('DATA ', sCommand) thenbeginFReceived := RightStr(sCommand, Length(sCommand)-5);WriteLn('200: 數(shù)據(jù)接收成功! ');AThread.Synchronize(DisplayData);endelse if SameText(sCommand, 'QUIT') th
43、en beginFLogEntry := ' 斷開同主機(jī) '+ + ' 的連接! 'AThread.Synchronize(AddLogEntry);Disconnect;endelse beginWriteLn('500: 無法識(shí)別的命令! ');FLogEntry := ' 無法識(shí)別命令: ' + sCommand;AThread.Synchronize(AddLogEntry);end;/endifend;end;procedure TFormMain.DisplayData();beginEdtData.Text := F
44、Received;end;procedure TFormMain.AddLogEntry();beginLbLog.Items.Add(FLogEntry);end;“啟動(dòng)”按鈕設(shè)置 IdTCPServer 的 Active 屬性為 True 來啟動(dòng)服務(wù)器, “停止”按鈕設(shè)置 Active 屬性 為 False 來關(guān)閉服務(wù)器。IdTCPServerConnect 方法作為 IdTCPServer 的 OnCorrect 事件響應(yīng)過程,向客戶端發(fā)送歡迎信息。 OnCorrect 事件在一個(gè)客戶連接請(qǐng)求被接受時(shí)發(fā)生,為該連接創(chuàng)建的線程 AThread 被作為參數(shù)傳遞給 IdTCPServerCon
45、nect 方法。IdTCPServerExecute 方 法 是 IdTCPServer 的 OnExecute 事 件 響 應(yīng) 過 程 。 OnExecute 事 件 在 TIdPeerThread 對(duì)象試圖執(zhí)行其 Run 方法時(shí)發(fā)生。 OnExecute 事件與通常的事件有所不同,其響應(yīng)過 程是在某個(gè)線程上下文中執(zhí)行的,參數(shù) AThread 就是調(diào)用它的線程。這一點(diǎn)很重要,它意味著可能有多個(gè) OnExecute 事件響應(yīng)過程被同時(shí)執(zhí)行。在連接被斷開或中斷前,OnExecute 事件響應(yīng)過程會(huì)被反復(fù)執(zhí)行。在IdTCPServerExecute方法中,首先讀入一條指令,然后對(duì)指令進(jìn)行判別。如果
46、是DATA指令,就解出數(shù)據(jù)并顯示它。如果收到的是QUIT指令,則斷開連接。需要特別指出的是,由于IdTCPServerExecute 方法在某一線程上下文中執(zhí)行,因此顯示數(shù)據(jù)和添加事件記錄都是將相應(yīng)的方法傳遞給 Synchronize 調(diào)用來完成的。運(yùn)行程序運(yùn)行客戶端和服務(wù)器程序,按如下流程進(jìn)行操作:1. 按服務(wù)器程序的“啟動(dòng)”按鈕啟動(dòng)服務(wù)器;2. 按客戶程序的“連接”按鈕,建立同服務(wù)器的連接;3. 在客戶程序的待發(fā)送數(shù)據(jù)編輯框中輸入“ Hello, Indy! ”,并按“發(fā)送”按鈕發(fā)送數(shù)據(jù);4. 按客戶程序的“斷開”按鈕,斷開同服務(wù)器的連接;5. 按服務(wù)器程序的“停止”按鈕停止服務(wù)器。用 S
47、ocket 接收和轉(zhuǎn)換數(shù)字和字符串?dāng)?shù)據(jù) 【大 中 小】【打印】【加入收藏】【關(guān)閉】瀏覽字號(hào) : 日期:2005-06-13 人氣: 60 出處: 作者: 7nightlove很多時(shí)候遠(yuǎn)程系統(tǒng)在執(zhí)行并發(fā)任務(wù)的時(shí)候,會(huì)把它接收到數(shù)據(jù)的長度以數(shù)字的形式發(fā)送出去。但用 socket 發(fā)送和接收數(shù)字型數(shù)據(jù)的時(shí)候 , 要考慮到一個(gè)問題:要根據(jù)網(wǎng)絡(luò)另一端機(jī)器的類型轉(zhuǎn)換數(shù)據(jù)。尤其 需要知道怎樣把要發(fā)送的數(shù)據(jù)格式(網(wǎng)絡(luò)格式)從本地機(jī)器的格式(主機(jī)格式)轉(zhuǎn)換成為行業(yè)標(biāo)準(zhǔn)格式。使 用 IPAddress.NetworkToHostOrder 可 以 把 數(shù) 據(jù) 從 網(wǎng) 絡(luò) 規(guī) 則 轉(zhuǎn) 換 為 主 機(jī) 格 式 , 下
48、 面 的ReceiveHeader 函數(shù)說明了它的用法, ReceiveHeader 函數(shù)實(shí)現(xiàn)過程如下:1 用 Socket.Receive 從遠(yuǎn)程機(jī)器接收數(shù)據(jù)。2 驗(yàn)證接收到的字節(jié)數(shù)是 4。3 Socket.Receive 返回一個(gè)字節(jié)型數(shù)組, BitConvert.ToInt32 把它轉(zhuǎn)換成數(shù)字型數(shù)值。4 最后, IPAddress.NetworkToHostOrder 把長數(shù)值轉(zhuǎn)換為主機(jī)格式。public int ReceiveHeader(Socket socket)int dataSize = -1; / errorbyte buffer = new byte4;int bytesR
49、ead = socket.Receive(buffer, 4,System.Net.Sockets.SocketFlags.None);if (4 = bytesRead)dataSize = BitConverter.ToInt32(buffer, 0);dataSize = IPAddress.NetworkToHostOrder(dataSize);else / error conditionreturn dataSize;下面再來看一下怎樣用多線程讀取的方法為每個(gè)字符串都建立連接, 從遠(yuǎn)程機(jī)器接收字符串型數(shù)據(jù)。 在這種情況下,要把字 節(jié)型數(shù)據(jù)轉(zhuǎn)換成 String 型對(duì)象。你可以根 據(jù)需
50、要用 ASCIIEncoding 或 UnicodeEncoding 類進(jìn)行轉(zhuǎn)換。 ReceiveDetail 函數(shù)按以下步驟實(shí)現(xiàn) (此函數(shù)必須在 ReceiveHeader 后調(diào)用, 因?yàn)?datasize 的值是從 ReceiveHeader 中得到的。)1 在 while 循環(huán)中調(diào)用 Socket.Receive ,直到無返回值為止。數(shù)據(jù)被讀入一個(gè)字節(jié)型數(shù)組。2 建立一個(gè) ASCIIEncoding 對(duì)象。3 調(diào)用 ASCIIEncoding.GetString 把字節(jié)型數(shù)組轉(zhuǎn)換成 String 對(duì)象,然后把它和先前讀入的數(shù)據(jù)連接。public string ReceiveDetail(
51、Socket socket, byte buffer,int dataSize)string response = ""int bytesReceived = 0;int totalBytesReceived = 0;while (0 < (bytesReceived =socket.Receive(buffer, (dataSize - totalBytesReceived), SocketFlags.None)totalBytesReceived += bytesReceived;ASCIIEncoding encoding = new ASCIIEncoding
52、(); response += encoding.GetString(buffer, 0, bytesReceived);return response;在 Delphi 7 中用 Indy 開發(fā) Socket 應(yīng)用程序2003-11-26 14:13:55虛度筆者在前一段的工作中, 需要開發(fā)一套簡單的網(wǎng)絡(luò)數(shù)據(jù)傳輸程序。由于平時(shí)常用 Delphi 做點(diǎn)開發(fā), 故此 次也不例外。 Delphi 7 中帶有兩套 TCP Socket 組件: Indy Socket 組件( IdTCPClient 和 IdTCPServer )和 Delphi 原生的 TCPSocket 組件(Clientsock
53、et 和 ServerSocket )。但是,Borland 已宣稱 ClientSocket 和 ServerSocket 組件即將被廢棄,建議用相應(yīng)的 Indy 組件來代替。 因此, 筆者使用 了 Indy 。本文在對(duì) Indy 進(jìn)行簡要介紹的基礎(chǔ)上, 創(chuàng)建了一組簡單的 TCPSocket 數(shù)據(jù)傳輸應(yīng)用來演示了 Indy 的使用方法。開放源代碼的 Internet 組件集 Internet Direct (Indy )Internet Direct (Indy )是一組開放源代碼的Internet 組件,涵蓋了幾乎所有流行的Internet 協(xié)議。Indy 用 Delphi 編寫,被包含在
54、 Delphi 6 , Kylix 1 和 C+ Builder 6 及以上各個(gè)版本的 Borland 開發(fā)環(huán)境中。 Indy曾經(jīng)叫做 WinShoes (雙關(guān)于 WinSockWindows的Socket庫),是由Chad乙Hower領(lǐng)導(dǎo)的一群開發(fā)者構(gòu)建的,可以從 Indy 的站點(diǎn) 上找到更多的信息并下載其新版本。到筆者撰寫 本文時(shí)為止, Indy 的最新穩(wěn)定版是 9.0.14 , Indy 10 也進(jìn)入了 Beta 測試階段。Delphi 7 中所帶的是 Indy 9 。在其的組件面板上,一共安裝有 100多個(gè) Indy 組件。使用這些組件你可以 開發(fā)基于各種協(xié)議的TCP客戶和服務(wù)器應(yīng)用程
55、序,并處理相關(guān)的編碼和安全問題。你可以通過前綴Id來識(shí) 別 Indy 組件。Indy 是阻塞式( Blocking )的當(dāng)你使用 Winsock 開發(fā)網(wǎng)絡(luò)應(yīng)用程序時(shí),從 Socket 中讀取數(shù)據(jù)或者向 Socket 寫入數(shù)據(jù)都是異步發(fā)生的, 這樣就不會(huì)阻斷程序中其它代碼的執(zhí)行。在收到數(shù)據(jù)時(shí),Winsock 會(huì)向應(yīng)用程序發(fā)送相應(yīng)的消息。這種訪問方式被稱作非阻塞式連接,它要求你對(duì)事件作出響應(yīng),設(shè)置狀態(tài)機(jī),并通常還需要一個(gè)等待循環(huán)。與通常的 Winsock 編程方法不同的是, Indy 使用了阻塞式 Socket 調(diào)用方式。阻塞式訪問更像是文件存取。 當(dāng)你讀取數(shù)據(jù),或是寫入數(shù)據(jù)時(shí),讀取和寫入函數(shù)將一
56、直等到相應(yīng)的操作完成后才返回。比如說,發(fā)起網(wǎng) 絡(luò)連接只需調(diào)用 Connect 方法并等待它返回,如果該方法執(zhí)行成功,在結(jié)束時(shí)就直接返回,如果未能成功 執(zhí)行,則會(huì)拋出相應(yīng)的異常。同文件訪問不同的是, Socket 調(diào)用可能會(huì)需要更長的時(shí)間,因?yàn)橐x寫的數(shù) 據(jù)可能不會(huì)立即就能準(zhǔn)備好(在很大程度上依賴于網(wǎng)絡(luò)帶寬) 。阻塞式 Socket 并非惡魔( Evil )長期以來,阻塞式 Socket 都遭到了毫無理由的攻擊。其實(shí)阻塞式 Socket 并非如通常所說的那樣可怕。這 還要從 Winsock 的發(fā)展說起。當(dāng) Socket 被從 Unix 移植到 Windows 時(shí),一個(gè)嚴(yán)重的問題立即就出現(xiàn)了。 U
57、nix 支持 fork ,客戶程序和服務(wù) 器都能夠 fork 新的進(jìn)程,并啟動(dòng)這些進(jìn)程,從而能夠很方便地使用阻塞式Socket 。而 Windows 3.x 既不支持 fork 也不支持多線程,當(dāng)使用阻塞式 Socket 時(shí),用戶界面就會(huì)被“鎖住”而無法響應(yīng)用戶輸入。為克服 Windows 3.x 的這一缺陷,微軟在 Winsock 中加入了異步擴(kuò)展,以使 Winsock 不會(huì)“鎖住”應(yīng)用程 序的主線程(也是唯一的線程) 。然而,這需要了一種完全不同的編程方式。 于是有些人為了掩飾這一弱點(diǎn), 就開始強(qiáng)烈地誹謗阻塞式 Socket 。當(dāng) Win32 出現(xiàn)的時(shí)候,它能夠很好地支持線程。但是既成的觀念已經(jīng)很難更改,并且說出去的話也無法收 回,因此對(duì)阻塞式 Socket 的誹謗繼續(xù)存在著。事實(shí)上,阻塞式 Socket 仍然是 Unix 實(shí)現(xiàn) Socke
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- TY/T 1110-2024體育賽事活動(dòng)參賽指引編制規(guī)范
- 科協(xié)課題立項(xiàng)申報(bào)書范文
- 如何撰寫社科課題申報(bào)書
- 叉車租賃帶司機(jī)合同范本
- 課題申報(bào)書哪里查
- 班級(jí)管理 課題立申報(bào)書
- 班級(jí)建設(shè)課題申報(bào)書
- 合同范本 銷售合同
- 周結(jié)算合同范例
- 深圳課題申報(bào)書格式
- GB/T 7251.3-2017低壓成套開關(guān)設(shè)備和控制設(shè)備第3部分:由一般人員操作的配電板(DBO)
- 工程質(zhì)量回訪記錄
- GB/T 2572-2005纖維增強(qiáng)塑料平均線膨脹系數(shù)試驗(yàn)方法
- 2023年江蘇省中學(xué)生生物奧林匹克競賽試題及答案
- 維修質(zhì)量檢驗(yàn)制度
- 食管支架植入術(shù)后護(hù)理課件
- 品質(zhì)控制計(jì)劃(QC工程圖)
- 海外派遣人員管理辦法
- 混凝土灌注樁質(zhì)量平行檢查記錄(鋼筋籠)
- 汽車營銷學(xué)(全套課件)
- 現(xiàn)澆墩臺(tái)身軸線偏位、全高豎直度檢測記錄表
評(píng)論
0/150
提交評(píng)論