利用Delphi編寫Socket通信程序_第1頁
利用Delphi編寫Socket通信程序_第2頁
利用Delphi編寫Socket通信程序_第3頁
利用Delphi編寫Socket通信程序_第4頁
利用Delphi編寫Socket通信程序_第5頁
已閱讀5頁,還剩31頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、Indy10Install All 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. IndySupe

2、rCore (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 order 4.5.1. dclIndyCore (in LibCore) 2. dclIndyProtocols (in LibProtocols) 3. dclSuperCore (in LibSuperCore)Only install this if you have compiled Supe

3、rCore. 利用Delphi編寫Socket通信程序2021-08-24 人氣:5925 出處:csdn 作者: dudunono 原作 一、Delphi與Socket計算機(jī)網(wǎng)絡(luò)是由一系列網(wǎng)絡(luò)通信協(xié)議組成的,其中的核心協(xié)議是傳輸層的TCP/IP和UDP協(xié)議。TCP是面向連接的,通信雙方保持一條通路,好比目前的 線,使用telnet登陸B(tài)BS,用的就是TCP協(xié)議;UDP是無連接的,通信雙方都不保持對方的狀態(tài),瀏覽器訪問Internet時使用的 協(xié)議就是基于UDP協(xié)議的。TCP和UDP協(xié)議都非常復(fù)雜,尤其是TCP協(xié)議,為了保證網(wǎng)絡(luò)傳輸?shù)恼_性和有效性,必須進(jìn)行一系列復(fù)雜的糾錯和排序等處理。Soc

4、ket是建立在傳輸層協(xié)議(主要是TCP和UDP)上的一種套接字標(biāo)準(zhǔn),最初是由美國加州Berkley大學(xué)提出,它定義兩臺計算機(jī)間進(jìn)行通信的標(biāo)準(zhǔn)也是一種編程標(biāo)準(zhǔn),如果說兩臺計算機(jī)是利用一個“通道“進(jìn)行通信,那么這個“通道“的兩端就是兩個套接字。套接字屏蔽了底層通信軟件和具體操作系統(tǒng)的差異,使得任何兩臺安裝了TCP協(xié)議軟件和實現(xiàn)了套接字標(biāo)準(zhǔn)的計算機(jī)之間的通信成為可能。微軟的Windows Socket標(biāo)準(zhǔn)(簡稱winsock)對Berkley的套接字標(biāo)準(zhǔn)進(jìn)行了擴(kuò)展,利用標(biāo)準(zhǔn)的Socket的方法,可以同任何平臺上的Socket進(jìn)行通信;利用其擴(kuò)展,可以更有效地實現(xiàn)在Windows平臺上計算機(jī)間的通信。

5、在Delphi中,其底層的Socket也應(yīng)該是Windows的Socket。Socket減輕了編寫計算機(jī)間通信軟件的難度,但總的說來還是相當(dāng)復(fù)雜的這一點在后面具體會講到;Inprise在Delphi中對Windows Socket進(jìn)行了有效的封裝,使得用戶可以很方便地編寫網(wǎng)絡(luò)通信程序。下面我們實例解讀在Delphi中如何利用Socket編寫通信程序。二、利用Delphi編寫Socket通信程序。下面是一個簡單的Socket通信程序,其中客戶機(jī)和效勞機(jī)是同一個程序,當(dāng)客戶機(jī)效勞器在一個memo1中輸入一段文字然后敲入回車,該段文字就可以顯示在效勞器(客戶機(jī))的memo2中,反之亦成立。具體步驟如

6、下:1、新建一個form,任意命名,不妨設(shè)之為chatForm;放上一個MainMenu(在Standard欄中),建立ListenItem、ConnectItem、Disconnect和Exit菜單項;在從Internet欄中選擇TServerSocket、TClientSocket添加到chatForm中,其中把TClientSocket的名字設(shè)為ClientSocket, port設(shè)為1025,默認(rèn)的active為false;把TServerSocket的名字設(shè)為ServerSocket,port設(shè)為1025,默認(rèn)的active為false,其他的不變;再放入兩個memo,一個命名為me

7、mo1,另外一個命名為memo2,其中把memo2的color設(shè)置為灰色,因為主要用來顯示對方的輸入。下面我們一邊編寫代碼一邊解釋原因。、雙擊ListemItem。寫入如下代碼:procedure TChatForm.ListenItemClick(Sender: TObject);beginListenItem.Checked := not ListenItem.Checked;if ListenItem.Checked thenbeginClientSocket.Active := False;ServerSocket.Active := True;endelsebeginif Serve

8、rSocket.Active thenServerSocket.Active := False;end;end;該程序段的說明如下:當(dāng)用戶選擇ListemItem時,該ListenItem取反,如果選中的話,說明處于Listen狀態(tài),讀者要了解的是:listen是Socket作為Server時一個專有的方法,如果處于listen,那么ServerSocket設(shè)置為活動狀態(tài);否那么,取消listen,那么關(guān)閉ServerSocket。實際上,只有用戶一開始選擇該菜單項,說明該程序用作Server。反之,如果用戶選擇ConnectItem,那么必然作為Client使用。、雙擊ConnectItem

9、,敲入以下代碼。procedure TChatForm.ConnectItemClick(Sender: TObject);beginif ClientSocket.Active then ClientSocket.Active := False;if InputQuery('Computer to connect to', 'Address Name:', Server) thenif Length(Server) > 0 thenwith ClientSocket dobeginHost := Server;Active := True;ListenI

10、tem.Checked := False;end;end;這段程序的主要功能就是當(dāng)用戶選擇ConnectItem菜單項時,設(shè)置應(yīng)用程序為客戶機(jī),彈出input框,讓用戶輸入效勞器的地址。這也就是我們不一開始固定ClientSocket的host的原因,這樣用戶可以動態(tài)地連接不同的效勞器。讀者需要了解的是主機(jī)地址只是Socket作為客戶機(jī)時具有的一個屬性,Socket作為效勞器時“一般“不用地址,因為它同本機(jī)綁定。4、在memo1的keydown方法中寫入如下代碼:procedure TChatForm.Memo1KeyDown(Sender: TObject; var Key: Word;Sh

11、ift: TShiftState);beginif Key = VK_Return thenif IsServer thenelseend;該段代碼的作用很明顯,就是開始發(fā)消息了。其中如果是Server的話,它只向第一個客戶機(jī)發(fā)消息,由于一個效勞器可以連接多個客戶機(jī),而同客戶機(jī)的每一個連接都由一個Socket來維Socket,而發(fā)送、接受消息的方法分別為send(sendto)和recv(recvfrom), Delphi對此進(jìn)行了封裝。、其余代碼的簡要介紹。procedure TChatForm.ServerSocketAccept(Sender: TObject;Socket: TCust

12、omWinSocket);beginIsServer := True;end;ServerSocket的Accept方法,當(dāng)客戶機(jī)第一次連接時完成,通過其參數(shù)可以認(rèn)為,它是在標(biāo)準(zhǔn)的accept方法后執(zhí)行的,因為有TCustomWinSocket這個參數(shù)類型,它應(yīng)該是標(biāo)準(zhǔn)Server方Socket的返回值。 procedure TChatForm.ClientSocketRead(Sender: TObject;Socket: TCustomWinSocket);beginend;procedure TChatForm.ServerSocketClientRead(Sender: TObject

13、;Socket: TCustomWinSocket);beginend;這兩段代碼分別是效勞器方和客戶機(jī)方在收到對方的消息時,由Delphi觸發(fā)的,作用是在memo2中顯示收到的消息。其中,ClientSocketRead中的Socket實際上就是Socket本身,而在procedure TChatForm.ServerSocketClientConnect(Sender: TObject;Socket: TCustomWinSocket);beginend;procedure TChatForm.ClientSocketDisconnect(Sender: TObject;Socket: T

14、CustomWinSocket);beginListenItemClick(nil);end;這兩段比擬簡單。其中ServerSocketClientConnect在ServerSocket收到一個新的連接時觸發(fā)。而ClientSocketDisconnect在ClientSocket發(fā)出Disconncet時觸發(fā)。procedure TChatForm.Exit1Click(Sender: TObject);beginServerSocket.Close;ClientSocket.Close;Close;end;procedure TChatForm.Disconnect1Click(Sen

15、der: TObject);beginClientSocket.Active := False;ServerSocket.Active := True;end;定調(diào)用了closesocket方法。三、標(biāo)準(zhǔn)Socket與Delphi中的Socket。標(biāo)準(zhǔn)的Socket的應(yīng)用程序框架如下:Server方: Socket() 新建一個SocketBind() 同效勞器地址邦定 Listen() Accept()block waitread()接受消息,在windows平臺中,方法為send(TCP),或者是sendto(UDP)處理效勞請求Write()發(fā)送消息,在windows平臺中,方法為sen

16、d(TCP), 或者為sendto(UDP)。Client方相對簡單:Socket()Connect()通過一定的port連接特定的效勞器,這是與效勞器建立連接Write()Read()。Socket可以是基于TCP的,也可以是基于UDP,同時Socket甚至建立在其他的協(xié)議,比方IPX/SPX,DECNet等。在新建一個Socket時,可以指定新建何類Socket。Bind()用來同效勞器的地址邦定,如果一個主機(jī)只有一個IP地址,實際上邦定的作用就相對多余了。Listen()開始監(jiān)聽網(wǎng)絡(luò),Accept()用于接受連接,其返回值是保持同客戶機(jī)聯(lián)系的Socket。在Delphi中,對于Windo

17、ws中的Socket進(jìn)行了有效的封裝。在Delphi中,按其繼承關(guān)系,可以分層兩類:一、TComponentTAbstractSocketTCustomSocketTCustomServerSocketTServerSocketTComponentTAbstractSocketTCustomSocketTClientSocket二、直接從TObject繼承過來:TObjectTCustomWinSocketTServerWinSocketTObjectTCustomWinSocketTClientWinSocketTObjectTCustomWinSocketTServerClientWinS

18、ocket可以看出第一類建立在TCustomSocket根底上,第二類建立在TCustomWinSocket的根底上。第一類建立在TComponet的根底上,第二類直接構(gòu)建在TObject根底上。因此如果用戶非常熟悉Socket并且想要編寫控制臺程序時,可以使用TCustomWinScoket類。同uses中可以看出,它們都在ScktComp.pas中實現(xiàn),而在schtComp.pas中,那么包含了winsock.pas文件,如果繼續(xù)深入winsock文件,在其中可以發(fā)現(xiàn)所有的Windows Socket的根本方法。實際上,如果你了解了標(biāo)準(zhǔn)Socket的應(yīng)用程序框架,對于使用Delphi編寫S

19、ocket應(yīng)用程序也就得心應(yīng)手了;這不是說你必須了解復(fù)雜的Socket中的標(biāo)準(zhǔn)函數(shù),也沒有必要,因為Delphi已經(jīng)為你做了很好的封裝了,這也正是Delphi的強(qiáng)勢所在,你只要了解那么一點點的根本框架。這是我對Delphi中的Socket應(yīng)用的理解,缺乏之處希望大家指正。同時也樂于為大家解答Delphi中有關(guān)Socket的問題。用Indy組件開發(fā)Socket應(yīng)用程序 創(chuàng)立時間:2021-3-16文章屬性:轉(zhuǎn)載文章提交:絕對零度今日瀏覽:23總共次數(shù):648 文章 虛度文章出處:yesky 筆者在前一段的工作中,需要開發(fā)一套簡單的網(wǎng)絡(luò)數(shù)據(jù)傳輸程序。由于平時常用Delphi做點開發(fā),故此次也不例外

20、。Delphi 7中帶有兩套TCP Socket組件:Indy Socket組件IdTCPClient和IdTCPServer和Delphi原生的TCP Socket組件ClientSocket和ServerSocket。但是,Borland已宣稱ClientSocket和ServerSocket組件即將被廢棄,建議用相應(yīng)的Indy組件來代替。因此,筆者使用了Indy。本文在對Indy進(jìn)行簡要介紹的根底上,創(chuàng)立了一組簡單的TCP Socket數(shù)據(jù)傳輸應(yīng)用來演示了Indy的使用方法。開放源代碼的Internet組件集Internet DirectIndyInternet DirectIndy是一

21、組開放源代碼的Internet組件,涵蓋了幾乎所有流行的Internet協(xié)議。Indy用Delphi編寫,被包含在Delphi 6,Kylix 1和C+ Builder 6及以上各個版本的Borland開發(fā)環(huán)境中。Indy曾經(jīng)叫做WinShoes雙關(guān)于WinSockWindows的Socket庫,是由Chad Z. Hower領(lǐng)導(dǎo)的一群開發(fā)者Delphi 7中所帶的是Indy 9。在其的組件面板上,一共安裝有100多個Indy組件。使用這些組件你可以開發(fā)基于各種協(xié)議的TCP客戶和效勞器應(yīng)用程序,并處理相關(guān)的編碼和平安問題。你可以通過前綴Id來識別Indy組件。Indy是阻塞式Blocking的

22、當(dāng)你使用Winsock開發(fā)網(wǎng)絡(luò)應(yīng)用程序時,從Socket中讀取數(shù)據(jù)或者向Socket寫入數(shù)據(jù)都是異步發(fā)生的,這樣就不會阻斷程序中其它代碼的執(zhí)行。在收到數(shù)據(jù)時,Winsock會向應(yīng)用程序發(fā)送相應(yīng)的消息。這種訪問方式被稱作非阻塞式連接,它要求你對事件作出響應(yīng),設(shè)置狀態(tài)機(jī),并通常還需要一個等待循環(huán)。與通常的Winsock編程方法不同的是,Indy使用了阻塞式Socket調(diào)用方式。阻塞式訪問更像是文件存取。當(dāng)你讀取數(shù)據(jù),或是寫入數(shù)據(jù)時,讀取和寫入函數(shù)將一直等到相應(yīng)的操作完成后才返回。比方說,發(fā)起網(wǎng)絡(luò)連接只需調(diào)用Connect方法并等待它返回,如果該方法執(zhí)行成功,在結(jié)束時就直接返回,如果未能成功執(zhí)行,那

23、么會拋出相應(yīng)的異常。同文件訪問不同的是,Socket調(diào)用可能會需要更長的時間,因為要讀寫的數(shù)據(jù)可能不會立即就能準(zhǔn)備好在很大程度上依賴于網(wǎng)絡(luò)帶寬。阻塞式Socket并非惡魔Evil長期以來,阻塞式Socket都遭到了毫無理由的攻擊。其實阻塞式Socket并非如通常所說的那樣可怕。這還要從Winsock的開展說起。當(dāng)Socket被從Unix移植到Windows時,一個嚴(yán)重的問題立即就出現(xiàn)了。Unix支持fork,客戶程序和效勞器都能夠fork新的進(jìn)程,并啟動這些進(jìn)程,從而能夠很方便地使用阻塞式Socket。而Windows 3.x既不支持fork也不支持多線程,當(dāng)使用阻塞式Socket時,用戶界面

24、就會被“鎖住而無法響應(yīng)用戶輸入。為克服Windows 3.x的這一缺陷,微軟在Winsock中參加了異步擴(kuò)展,以使Winsock不會“鎖住應(yīng)用程序的主線程也是唯一的線程。然而,這需要了一種完全不同的編程方式。于是有些人為了掩飾這一弱點,就開始強(qiáng)烈地誹謗阻塞式Socket。當(dāng)Win32出現(xiàn)的時候,它能夠很好地支持線程。但是既成的觀念已經(jīng)很難更改,并且說出去的話也無法收回,因此對阻塞式Socket的誹謗繼續(xù)存在著。事實上,阻塞式Socket仍然是Unix實現(xiàn)Socket的唯一方式,并且它工作得很好。阻塞式Socket的優(yōu)點歸結(jié)起來,在Windows上使用阻塞式Socket開發(fā)應(yīng)用程序具有如下優(yōu)點:

25、編程簡單阻塞式Socket應(yīng)用程序很容易編寫。所有的用戶代碼都寫在同一個地方,并且順序執(zhí)行。 容易向Unix移植由于Unix也使用阻塞式Socket,編寫可移植的代碼就變得比擬容易。Indy就是利用這一點來實現(xiàn)其多平臺支持而又單一源代碼的設(shè)計。 很好地利用了線程技術(shù)阻塞式Socket是順序執(zhí)行的,其固有的封裝特性使得它能夠很容易地使用到線程中。 阻塞式Socket的缺點事物都具有兩面性,阻塞式Socket也不例外。它的一個主要的缺點就是使客戶程序的用戶界面“凍結(jié)。當(dāng)在程序的主線程中進(jìn)行阻塞式Socket調(diào)用時,由于要等待Socket調(diào)用完成并返回,這段時間就不能處理用戶界面消息,使得Updat

26、e、Repaint以及其它消息得不到及時響應(yīng),從而導(dǎo)致用戶界面被“凍結(jié)。使用TIdAntiFreeze對抗“凍結(jié)Indy使用一個特殊的組件TIdAntiFreeze來透明地解決客戶程序用戶界面“凍結(jié)的問題。TIdAntiFreeze在Indy內(nèi)部定時中斷對棧的調(diào)用,并在中斷期間調(diào)用Application.ProcessMessages方法處理消息,而外部的Indy調(diào)用繼續(xù)保存阻塞狀態(tài),就好似TIdAntiFreeze對象不存在一樣。你只要在程序中的任意地方添加一個TIdAntiFreeze對象,就能在客戶程序中利用到阻塞式Socket的所有優(yōu)點而避開它的一些顯著缺點。Indy使用了線程技術(shù)阻塞

27、式Socekt通常都采用線程技術(shù),Indy也是如此。從最底層開始,Indy的設(shè)計都是線程化的。因此用Indy創(chuàng)立效勞器和客戶程序跟在Unix下十分相似,并且Delphi的快速開發(fā)環(huán)境和Indy對WinSock的良好封裝使得應(yīng)用程序創(chuàng)立更加容易。Indy效勞器模型一個典型的Unix效勞器有一個或多個監(jiān)聽進(jìn)程,它們不停地監(jiān)聽進(jìn)入的客戶連接請求。對于每一個需要效勞的客戶,都fork一個新進(jìn)程來處理該客戶的所有事務(wù)。這樣一個進(jìn)程只處理一個客戶連接,編程就變得十分容易。Indy效勞器工作原理同Unix效勞器十分類似,只是Windows不像Unix那樣支持fork,而是支持線程,因此Indy效勞器為每一個

28、客戶連接分配一個線程。圖1顯示了Indy效勞器的工作原理。Indy效勞器組件創(chuàng)立一個同應(yīng)用程序主線程別離的監(jiān)聽線程來監(jiān)聽客戶連接請求,對于接受的每一個客戶,都創(chuàng)立一個新的線程來為該客戶提供效勞,所有與這一客戶相關(guān)的事務(wù)都由該線程來處理。使用組件TIdThreadMgrPool,Indy還支持線程池。 上一頁 1 2 3 4 下一頁線程與Indy客戶程序Indy客戶端組件并未使用線程。但是在一些高級的客戶程序中,程序員可以在自定義的線程中使用Indy客戶端組件,以使用戶界面更加友好。簡單的Indy應(yīng)用例如下面將創(chuàng)立一個簡單的TCP客戶程序和一個簡單的TCP效勞器來演示Indy的根本使用方法??蛻?/p>

29、程序使用TCP協(xié)議同效勞器連接,并向效勞器發(fā)送用戶所輸入數(shù)據(jù)。效勞器支持兩條命令:DATA和QUIT。在DATA命令后跟隨要發(fā)送的數(shù)據(jù),并用空格將命令字DATA和數(shù)據(jù)分隔開。表單布局建立一個工程組,添加一個客戶程序工程和一個效勞器工程??蛻舫绦蚝托谄鞒绦虻谋韱尾季秩缤?和圖3所示。客戶程序表單上放置了TIdTCPClient組件,效勞器程序表單上放置了TIdTCPServer組件。為防止客戶程序“凍結(jié),還在其表單上放置TIdAntiFreeze組件??蛻舫绦蚝托谄鞒绦虻谋韱紊隙挤胖糜蠺ListBox組件,用來顯示通信記錄??蛻舫绦虼a客戶程序片斷如代碼列表1所示。代碼列表1procedur

30、e TFormMain.BtnConnectClick(Sender: TObject);beginIdTCPClient.Host := EdtHost.Text;IdTCPClient.Port := StrToInt(EdtPort.Text);with IdTCPClient dobegintryConnect(5000);tryBtnConnect.Enabled := False;BtnSend.Enabled := True;BtnDisconnect.Enabled := True;exceptIdTCPClient.Disconnect();end;/end tryexcep

31、tend;/end tryend;/end withend;procedure TFormMain.BtnSendClick(Sender: TObject);beginwith IdTCPClient dobegintryWriteLn('DATA ' + EdtData.Text);exceptIdTCPClient.Disconnect();BtnConnect.Enabled := True;BtnSend.Enabled := False;BtnDisconnect.Enabled := False;end;/end tryend;/end withend;proce

32、dure TFormMain.BtnDisconnectClick(Sender: TObject);varReceived: string;begintryIdTCPClient.WriteLn('QUIT');finallyIdTCPClient.Disconnect();BtnConnect.Enabled := True;BtnSend.Enabled := False;BtnDisconnect.Enabled := False;end;/end tryend; 在“連接按鈕事件響應(yīng)過程中,首先根據(jù)用戶輸入設(shè)置IdTCPClient的主機(jī)和端口,并調(diào)用IdTCPCli

33、ent的Connect方法向效勞器發(fā)出連接請求。然后調(diào)用ReadLn方法讀取效勞器應(yīng)答數(shù)據(jù)。在“發(fā)送按鈕事件響應(yīng)過程中,調(diào)用WriteLn方法寫DATA命令,向效勞器發(fā)送數(shù)據(jù)。在“斷開按鈕事件響應(yīng)過程中,向效勞器發(fā)送QUIT命令,并調(diào)用Disconnect方法斷開連接。程序中還包含有通信信息記錄和異常處理的代碼。效勞器程序代碼效勞器程序片斷如代碼列表2所示。代碼列表2procedure TFormMain.BtnStartClick(Sender: TObject);beginIdTCPServer.DefaultPort := StrToInt(EdtPort.Text);IdTCPServ

34、er.Active := True;BtnStart.Enabled := False;BtnStop.Enabled := True;end;procedure TFormMain.BtnStopClick(Sender: TObject);beginIdTCPServer.Active := False;BtnStart.Enabled := True;BtnStop.Enabled := False;end;procedure TFormMain.IdTCPServerConnect(AThread: TIdPeerThread);begin+ ' 的連接請求已被接納!'

35、);end;procedure TFormMain.IdTCPServerExecute(AThread: TIdPeerThread);varsCommand: string;beginwith AThread.Connection dobeginsCommand := ReadLn();FLogEntry := sCommand + ' 來自于主機(jī) 'AThread.Synchronize(AddLogEntry);if AnsiStartsText('DATA ', sCommand) thenbeginFReceived := RightStr(sCom

36、mand, Length(sCommand)-5);WriteLn('200: 數(shù)據(jù)接收成功!');AThread.Synchronize(DisplayData);endelse if SameText(sCommand, 'QUIT') then beginFLogEntry := '斷開同主機(jī) '+ ' 的連接!'AThread.Synchronize(AddLogEntry);Disconnect;endelse beginWriteLn('500: 無法識別的命令!');FLogEntry := '

37、;無法識別命令:' + sCommand;AThread.Synchronize(AddLogEntry);end;/endifend;end;procedure TFormMain.DisplayData();beginEdtData.Text := FReceived;end;procedure TFormMain.AddLogEntry();beginend; “啟動按鈕設(shè)置IdTCPServer 的Active屬性為True來啟動效勞器,“停止按鈕設(shè)置Active屬性為False來關(guān)閉效勞器。IdTCPServerConnect方法作為IdTCPServer 的OnCorrec

38、t事件響應(yīng)過程,向客戶端發(fā)送歡送信息。OnCorrect事件在一個客戶連接請求被接受時發(fā)生,為該連接創(chuàng)立的線程AThread被作為參數(shù)傳遞給IdTCPServerConnect方法。IdTCPServerExecute方法是IdTCPServer 的OnExecute事件響應(yīng)過程。OnExecute事件在TIdPeerThread對象試圖執(zhí)行其Run方法時發(fā)生。OnExecute事件與通常的事件有所不同,其響應(yīng)過程是在某個線程上下文中執(zhí)行的,參數(shù)AThread就是調(diào)用它的線程。這一點很重要,它意味著可能有多個OnExecute事件響應(yīng)過程被同時執(zhí)行。在連接被斷開或中斷前,OnExecute事件

39、響應(yīng)過程會被反復(fù)執(zhí)行。在IdTCPServerExecute方法中,首先讀入一條指令,然后對指令進(jìn)行判別。如果是DATA指令,就解出數(shù)據(jù)并顯示它。如果收到的是QUIT指令,那么斷開連接。需要特別指出的是,由于IdTCPServerExecute方法在某一線程上下文中執(zhí)行,因此顯示數(shù)據(jù)和添加事件記錄都是將相應(yīng)的方法傳遞給Synchronize調(diào)用來完成的。運行程序運行客戶端和效勞器程序,按如下流程進(jìn)行操作:1. 按效勞器程序的“啟動按鈕啟動效勞器;2. 按客戶程序的“連接按鈕,建立同效勞器的連接;3. 在客戶程序的待發(fā)送數(shù)據(jù)編輯框中輸入“Hello, Indy!,并按“發(fā)送按鈕發(fā)送數(shù)據(jù);4. 按

40、客戶程序的“斷開按鈕,斷開同效勞器的連接;5. 按效勞器程序的“停止按鈕停止效勞器。 用Socket接收和轉(zhuǎn)換數(shù)字和字符串?dāng)?shù)據(jù)【大 中 小】【打印】【參加收藏】【關(guān)閉】瀏覽字號:日期:2022-06-13 人氣:60 出處:codeguru 作者: 7nightlove 很多時候遠(yuǎn)程系統(tǒng)在執(zhí)行并發(fā)任務(wù)的時候,會把它接收到數(shù)據(jù)的長度以數(shù)字的形式發(fā)送出去。但用socket發(fā)送和接收數(shù)字型數(shù)據(jù)的時候,要考慮到一個問題:要根據(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.NetworkToHostOrde

41、r可以把數(shù)據(jù)從網(wǎng)絡(luò)規(guī)那么轉(zhuǎn)換為主機(jī)格式,下面的ReceiveHeader函數(shù)說明了它的用法,ReceiveHeader函數(shù)實現(xiàn)過程如下:1 用Socket.Receive從遠(yuǎn)程機(jī)器接收數(shù)據(jù)。 2 驗證接收到的字節(jié)數(shù)是4。3 Socket.Receive返回一個字節(jié)型數(shù)組,BitConvert.ToInt32把它轉(zhuǎn)換成數(shù)字型數(shù)值。4 最后,IPAddress.NetworkToHostOrder把長數(shù)值轉(zhuǎn)換為主機(jī)格式。public int ReceiveHeader(Socket socket) int dataSize = -1; / error byte buffer = new byte4

42、; int bytesRead = socket.Receive(buffer, 4, if (4 = bytesRead) dataSize = BitConverter.ToInt32(buffer, 0); dataSize = IPAddress.NetworkToHostOrder(dataSize); else / error condition return dataSize; 下面再來看一下怎樣用多線程讀取的方法為每個字符串都建立連接,從遠(yuǎn)程機(jī)器接收字符串型數(shù)據(jù)。在這種情況下,要把字節(jié)型數(shù)據(jù)轉(zhuǎn)換成String型對象。你可以根據(jù)需要用ASCIIEncoding或UnicodeEn

43、coding類進(jìn)行轉(zhuǎn)換。ReceiveDetail函數(shù)按以下步驟實現(xiàn)此函數(shù)必須在ReceiveHeader后調(diào)用,因為datasize的值是從ReceiveHeader中得到的。1 在while循環(huán)中調(diào)用Socket.Receive,直到無返回值為止。數(shù)據(jù)被讀入一個字節(jié)型數(shù)組。2 建立一個ASCIIEncoding對象。3 調(diào)用ASCIIEncoding.GetString把字節(jié)型數(shù)組轉(zhuǎn)換成String對象,然后把它和先前讀入的數(shù)據(jù)連接。public string ReceiveDetail(Socket socket, byte buffer, int dataSize) string re

44、sponse = "" int bytesReceived = 0; int totalBytesReceived = 0; while (0 < (bytesReceived = socket.Receive(buffer, (dataSize - totalBytesReceived), SocketFlags.None) totalBytesReceived += bytesReceived; ASCIIEncoding encoding = new ASCIIEncoding(); response += encoding.GetString(buffer,

45、0, bytesReceived); return response;在Delphi 7 中用Indy開發(fā)Socket應(yīng)用程序 2021-11-26 14:13:55 虛度 筆者在前一段的工作中,需要開發(fā)一套簡單的網(wǎng)絡(luò)數(shù)據(jù)傳輸程序。由于平時常用Delphi做點開發(fā),故此次也不例外。Delphi 7中帶有兩套TCP Socket組件:Indy Socket組件IdTCPC lient和IdTCPServer和Delphi原生的TCP Socket組件ClientSocket和ServerSocket。但是,Borland已宣稱ClientSocket和ServerSocket組件即將被廢棄,建議

46、用相應(yīng)的Indy組件來代替。因此,筆者使用了Indy。本文在對Indy進(jìn)行簡要介紹的根底上,創(chuàng)立了一組簡單的TCP Socket數(shù)據(jù)傳輸應(yīng)用來演示了Indy的使用方法。開放源代碼的Internet組件集Internet DirectIndyInternet DirectIndy是一組開放源代碼的Internet組件,涵蓋了幾乎所有流行的Internet協(xié)議。Indy用Delphi編寫,被包含在Delphi 6,Kylix 1和C+ Builder 6及以上各個版本的Borland開發(fā)環(huán)境中。Indy曾經(jīng)叫做WinShoes雙關(guān)于WinSockDelphi 7中所帶的是Indy 9。在其的組件面

47、板上,一共安裝有100多個Indy組件。使用這些組件你可以開發(fā)基于各種協(xié)議的TCP客戶和效勞器應(yīng)用程序,并處理相關(guān)的編碼和平安問題。你可以通過前綴Id來識別Indy組件。Indy是阻塞式Blocking的當(dāng)你使用Winsock開發(fā)網(wǎng)絡(luò)應(yīng)用程序時,從Socket中讀取數(shù)據(jù)或者向Socket寫入數(shù)據(jù)都是異步發(fā)生的,這樣就不會阻斷程序中其它代碼的執(zhí)行。在收到數(shù)據(jù)時,Winsock會向應(yīng)用程序發(fā)送相應(yīng)的消息。這種訪問方式被稱作非阻塞式連接,它要求你對事件作出響應(yīng),設(shè)置狀態(tài)機(jī),并通常還需要一個等待循環(huán)。與通常的Winsock編程方法不同的是,Indy使用了阻塞式Socket調(diào)用方式。阻塞式訪問更像是文件

48、存取。當(dāng)你讀取數(shù)據(jù),或是寫入數(shù)據(jù)時,讀取和寫入函數(shù)將一直等到相應(yīng)的操作完成后才返回。比方說,發(fā)起網(wǎng)絡(luò)連接只需調(diào)用Connect方法并等待它返回,如果該方法執(zhí)行成功,在結(jié)束時就直接返回,如果未能成功執(zhí)行,那么會拋出相應(yīng)的異常。同文件訪問不同的是,Socket調(diào)用可能會需要更長的時間,因為要讀寫的數(shù)據(jù)可能不會立即就能準(zhǔn)備好在很大程度上依賴于網(wǎng)絡(luò)帶寬。阻塞式Socket并非惡魔Evil長期以來,阻塞式Socket都遭到了毫無理由的攻擊。其實阻塞式Socket并非如通常所說的那樣可怕。這還要從Winsock的開展說起。當(dāng)Socket被從Unix移植到Windows時,一個嚴(yán)重的問題立即就出現(xiàn)了。Uni

49、x支持fork,客戶程序和效勞器都能夠fork新的進(jìn)程,并啟動這些進(jìn)程,從而能夠很方便地使用阻塞式Socket。而Windows 3.x既不支持fork也不支持多線程,當(dāng)使用阻塞式Socket時,用戶界面就會被“鎖住而無法響應(yīng)用戶輸入。為克服Windows 3.x的這一缺陷,微軟在Winsock中參加了異步擴(kuò)展,以使Winsock不會“鎖住應(yīng)用程序的主線程也是唯一的線程。然而,這需要了一種完全不同的編程方式。于是有些人為了掩飾這一弱點,就開始強(qiáng)烈地誹謗阻塞式Socket。當(dāng)Win32出現(xiàn)的時候,它能夠很好地支持線程。但是既成的觀念已經(jīng)很難更改,并且說出去的話也無法收回,因此對阻塞式Socket

50、的誹謗繼續(xù)存在著。事實上,阻塞式Socket仍然是Unix實現(xiàn)Socket的唯一方式,并且它工作得很好。阻塞式Socket的優(yōu)點歸結(jié)起來,在Windows上使用阻塞式Socket開發(fā)應(yīng)用程序具有如下優(yōu)點: 編程簡單阻塞式Socket應(yīng)用程序很容易編寫。所有的用戶代碼都寫在同一個地方,并且順序執(zhí)行。 容易向Unix移植由于Unix也使用阻塞式Socket,編寫可移植的代碼就變得比擬容易。Indy就是利用這一點來實現(xiàn)其多平臺支持而又單一源代碼的設(shè)計。 很好地利用了線程技術(shù)阻塞式Socket是順序執(zhí)行的,其固有的封裝特性使得它能夠很容易地使用到線程中。阻塞式Socket的弱點事物都具有兩面性,阻塞式

51、Socket也不例外。它的一個主要的缺點就是使客戶程序的用戶界面“凍結(jié)。當(dāng)在程序的主線程中進(jìn)行阻塞式Socket調(diào)用時,由于要等待Socket調(diào)用完成并返回,這段時間就不能處理用戶界面消息,使得Update、Repaint以及其它消息得不到及時響應(yīng),從而導(dǎo)致用戶界面被“凍結(jié)。使用TIdAntiFreeze對抗“凍結(jié)Indy使用一個特殊的組件TIdAntiFreeze來透明地解決客戶程序用戶界面“凍結(jié)的問題。TIdAntiFreeze在Indy內(nèi)部定時中斷對棧的調(diào)用,并在中斷期間調(diào)用Application.ProcessMessages方法處理消息,而外部的Indy調(diào)用繼續(xù)保存阻塞狀態(tài),就好似T

52、IdAntiFreeze對象不存在一樣。你只要在程序中的任意地方添加一個TIdAntiFreeze對象,就能在客戶程序中利用到阻塞式Socket的所有優(yōu)點而避開它的一些顯著缺點。Indy使用了線程技術(shù)阻塞式Socekt通常都采用線程技術(shù),Indy也是如此。從最底層開始,Indy的設(shè)計都是線程化的。因此用Indy創(chuàng)立效勞器和客戶程序跟在Unix下十分相似,并且Delphi的快速開發(fā)環(huán)境和Indy對WinSock的良好封裝使得應(yīng)用程序創(chuàng)立更加容易。Indy效勞器模型一個典型的Unix效勞器有一個或多個監(jiān)聽進(jìn)程,它們不停地監(jiān)聽進(jìn)入的客戶連接請求。對于每一個需要效勞的客戶,都fork一個新進(jìn)程來處理該

53、客戶的所有事務(wù)。這樣一個進(jìn)程只處理一個客戶連接,編程就變得十分容易。Indy效勞器工作原理同Unix效勞器十分類似,只是Windows不像Unix那樣支持fork,而是支持線程,因此Indy效勞器為每一個客戶連接分配一個線程。圖1顯示了Indy效勞器的工作原理。Indy效勞器組件創(chuàng)立一個同應(yīng)用程序主線程別離的監(jiān)聽線程來監(jiān)聽客戶連接請求,對于接受的每一個客戶,都創(chuàng)立一個新的線程來為該客戶提供效勞,所有與這一客戶相關(guān)的事務(wù)都由該線程來處理。使用組件TIdThreadMgrPool,Indy還支持線程池。圖1 Indy效勞器工作原理線程與Indy客戶程序Indy客戶端組件并未使用線程。但是在一些高級

54、的客戶程序中,程序員可以在自定義的線程中使用Indy客戶端組件,以使用戶界面更加友好。簡單的Indy應(yīng)用例如下面將創(chuàng)立一個簡單的TCP客戶程序和一個簡單的TCP效勞器來演示Indy的根本使用方法??蛻舫绦蚴褂肨CP協(xié)議同效勞器連接,并向效勞器發(fā)送用戶所輸入數(shù)據(jù)。效勞器支持兩條命令:DATA和QUIT。在DATA命令后跟隨要發(fā)送的數(shù)據(jù),并用空格將命令字DATA和數(shù)據(jù)分隔開。表單布局建立一個工程組,添加一個客戶程序工程和一個效勞器工程??蛻舫绦蚝托谄鞒绦虻谋韱尾季秩缤?和圖3所示??蛻舫绦虮韱紊戏胖昧薚IdTCPClient組件,效勞器程序表單上放置了TIdTCPServer組件。為防止客戶程序“凍結(jié),還在其表單上放置TIdAntiFreeze組件??蛻舫绦蚝托谄鞒绦虻谋韱紊隙挤胖糜蠺ListBox組件,用來顯示通信記錄。圖2 簡單的TCP客戶程序表單圖3 簡單的TCP效勞器程序表單在Delphi 7 中用Indy開發(fā)Socket應(yīng)用程序虛度2021-11-26 14:13:55客戶程序代碼客戶程序片斷如代碼列表1所示。代碼列表1procedure TFormMain.BtnConnectClick(Sender: TObject);beginIdTCPClient.Host := EdtHost.Text;IdTCPClient.Port

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論