indy 文件傳輸原理_第1頁
indy 文件傳輸原理_第2頁
indy 文件傳輸原理_第3頁
indy 文件傳輸原理_第4頁
indy 文件傳輸原理_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、還是研究 INDY控件的應(yīng)用,發(fā)現(xiàn)網(wǎng)上很少實例可以使用,于是我就一邊測一邊理解這兩個主要控件的應(yīng)用方法。網(wǎng)上有 客戶端傳大文件 >服務(wù)端 的例子但卻找不到 服務(wù)端傳大文件 >客戶端 的例子上次測試成功過一個 demo 就是服務(wù)端反傳給客戶端一個文本文件的DEMO(詳細(xì)請看:/read.php?tid=1061),于是我就在想,既然可以反傳文本文件,應(yīng)該也是可以反傳大文件,服務(wù)端傳給客戶端,應(yīng)該也是可以像客戶端傳給服務(wù)端那樣的。于是我又深入研究了一次,果然是可以的。其實 服務(wù)端和客戶端 都是客戶互相向?qū)Ψ絺魑?/p>

2、件的。但是呢,有一點不同的是,服務(wù)端是被動的,客戶端是主動的,服務(wù)端要給客戶端傳文件的話,需要客戶端向服務(wù)端發(fā)一個指令,這樣服務(wù)端才知道是向哪個客戶端發(fā)送文件流。關(guān)鍵就是 ReadBuffer 和 WriteBuffer兩個方法。先看看這兩個方法是做什么的,在 DELPHI中 查到這個函數(shù)的方法定義是這樣的procedure ReadBuffer(var Buffer; Count: Longint);描述:Use ReadBuffer to read Count bytes from the stream into a buffer in cases where the number ofb

3、ytes is known and fixed, for example when reading in structures. ReadBuffer is used internallyfor loading from a stream and copying from a stream.大致的意思:使用 ReadBuffer 從流中取讀一定數(shù)目(Count)字節(jié)的數(shù)據(jù)放進(jìn)一個緩存區(qū)(buffer)ReadBuffer calls Read to do the actual reading. If Count bytes cannot be read from the stream,an E

4、ReadError exception is raised.如果不能讀數(shù)據(jù)流 就會報錯很明顯 這個方法是從數(shù)據(jù)流里讀取一定長度 然后放到緩存區(qū)里的,所以 應(yīng)該不難理解procedure ReadBuffer(var Buffer; Count: Longint)的意思就是 從數(shù)據(jù)流里讀 count 長的數(shù)據(jù) 放到緩存區(qū) Buffer里。那說到這里 ,可能會有寫朋友 會問,什么是緩存區(qū)Buffer?OK! 我告訴你,這個緩存區(qū) Buffer 是 你自己定義好的一塊內(nèi)存空間。你可以定義 1M 也可以定義2M定義的方法非常簡單,就是Buffer: array0.1023 of Byte;上面就定義好

5、了一個 1024字節(jié)的緩存區(qū)。OK 這個不是討論的重點,你只需要明白 這個Buffer是你自己程序開辟的一塊內(nèi)存空間 ,就夠了??吹竭@里 你應(yīng)該明白了吧,procedure ReadBuffer(var Buffer; Count: Longint) 的作用了,就是從數(shù)據(jù)流里去讀一塊長度為 count的數(shù)據(jù),然后放到我的內(nèi)存緩存區(qū) Buffer中。這個時候你可能會又有一個疑問了,這個數(shù)據(jù)流是什么東東?很好,這個正是我要給你說的重點,數(shù)據(jù)流就是一個 socket 里面使用到的傳輸?shù)囊粋€東西,很抽象?是不是?總之,你理解成為水流會比較好理解一些,看過在線電影么?那些流媒體也是一種數(shù)據(jù)流。就像水一樣

6、流到你的電 腦,你的電腦不停接受,不停播放,下載文件也是一種數(shù)據(jù)流,只是你的電腦沒有把它播放而是保存起來了而已??傊褪且婚L串的數(shù)據(jù),有著順序的一串?dāng)?shù)據(jù),兩個連接只要有數(shù)據(jù)傳輸,就會產(chǎn)生數(shù)據(jù)流,所以說客戶端和服務(wù)端傳輸?shù)木褪沁@個所謂的數(shù)據(jù)流!那么 怎么去捕獲這些數(shù)據(jù)流呢,捕獲的是什么數(shù)據(jù)流呢?INDY控件里很多控件都有數(shù)據(jù)流的捕獲函數(shù),INDY控件里的方法就是用來捕獲相應(yīng)的數(shù)據(jù)流的。例如:在 客戶端(IdTCPClient1 是一個IdTCPClient對象)來看:IdTCPClient1.ReadBuffer(Buff, ReadCount);客戶端讀取服務(wù)端傳來的數(shù)據(jù)流,讀取ReadCou

7、nt長度的數(shù)據(jù)放到內(nèi)存的緩存區(qū)Buff中同樣道理,WriteBuffer 的作用就恰好相反,IdTCPClient1.WriteBuffer(Buff, ReadCount);客戶端從緩存區(qū)中讀ReadCount長度的數(shù)據(jù),放到朝服務(wù)端傳輸?shù)臄?shù)據(jù)流里那么在服務(wù)端來說,又是怎么和傳數(shù)據(jù)流的呢?是IdTCPserver1.ReadBuffer(Buff, ReadCount)和IdTCPserver1.WriteBuffer(Buff, ReadCount)嗎?如果你這樣想 我很高興,因為你可以舉一反三了,但如果你這樣寫入程序中,程序會報錯的。為什么?原因就是服務(wù)端對應(yīng)的是多個客戶端的連接,它本身

8、是多線程,每個線程各自對應(yīng)著一個客戶端(INDY里是這樣的)。也就是說,你的服務(wù)器里,只要有一 個服務(wù)端(IdTCPserver對象 IdTCPserver1),它就可以監(jiān)聽并且處理很多不同的客戶端傳過來的請求。所以說,如果你直接用IdTCPserver1.ReadBuffer(Buff, ReadCount)和IdTCPserver1.WriteBuffer(Buff, ReadCount)是不行的,因為你不能告訴服務(wù)端到底把這個數(shù)據(jù)傳輸給哪個和它建立連接的客戶端。讓他同時傳給所有的客戶端嗎?那服務(wù)端是不可能做得 到的,因為數(shù)據(jù)流會分散,并且會沖突。那服務(wù)端是怎么來處理和區(qū)分不同的客戶端的呢

9、?在 IdTCPserver對象的方法事件里,看看他們的方法定義:procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);procedure TForm1.IdTCPServer1Exception(AThread: TIdPeerThread; AException: Except

10、ion);看到了么,很多方法里都有一個AThread: TIdPeerThread,沒錯,這個就是客戶端了,它代表了一個客戶端。比方說TForm1.IdTCPServer1Connect(AThread: TIdPeerThread); 里的 AThread ,就是只剛和它建立連接的客戶端。procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);里的AThread 就是正在進(jìn)行交流的客戶端。所以,服務(wù)端就是通過 AThread 來對不同的客戶端進(jìn)行區(qū)分和處理的。說道這里,你就應(yīng)該明白了 服務(wù)端的對數(shù)據(jù)流的讀寫是在AThread的

11、方法屬性里的如:AThread.Connection.WriteBuffer(Buf, ReadCount);就是給建立連接的客戶端發(fā)數(shù)據(jù)流,從緩存區(qū)Buf里讀ReadCount長度的數(shù)據(jù)然后寫到和客戶端AThread連接的數(shù)據(jù)流中去反過來也是一樣:AThread.Connection.ReadBuffer(Buf, ReadCount);就是從與客戶端AThread連接的數(shù)據(jù)流中讀取 ReadCount 長度的數(shù)據(jù)放到內(nèi)存緩存區(qū)Buf中說到這里,你可能就已經(jīng)都明白了吧,不過你可能還會有一個問題,那,如果是傳輸文件的話,這個數(shù)據(jù)流是怎么傳的呢?整個過程是這樣的:不管服務(wù)端給客戶端傳還是客戶端給

12、服務(wù)端傳,其實過程都是一樣:為了便于理解,這里畫一個圖,A 要傳輸一個文件文件test.rar給 BA ->B分解動作A->創(chuàng)建文件流(fstream),用文件流的方法(fstream.ReadBuffer)將test.rar一段一段讀取然后放到 Buffer中,然后用AThread.Connection.WriteBuffer將Buffer的數(shù)據(jù)寫進(jìn)要給B傳輸?shù)臄?shù)據(jù)流中|B->創(chuàng)建文件流(ftmpStream)->讀取A傳過來的數(shù)據(jù)流(IdTCPClient1.ReadBuffer),用文件流的方法(ftmpStream.WriteBuffer),將緩沖區(qū)(Buffe

13、r)中的數(shù)據(jù)寫進(jìn)本地文件總之:文件 test.rar >A的Buffer>數(shù)據(jù)流>B的Buffer>B的文件 test.rar| | | |文件流的方法 數(shù)據(jù)流的方法 數(shù)據(jù)流的方法 文件流的方法| | | | | | | | | |fstream.ReadBuffer | | | | | | | | | | | |AThread.Connection.WriteBuffer | | |IdTCPClient1.ReadBuffer |ftmpStream.WriteBuffer以我的經(jīng)驗,感覺最難理解的就是 文件流和數(shù)據(jù)流的讀寫混淆在一起,初學(xué)的時候特別費勁??吹缴厦娴?/p>

14、流程,你應(yīng)該明白了吧,其實傳輸一個文件,并不是僅僅對數(shù)據(jù)流的處理,還有的是文件流的處理。但是,文件流和數(shù)據(jù)流其實都是很類似的(都是ReadBuffer和WriteBuffer)。只要你分清是哪個對象作出的動作就可以了。好了,說到這里都是空洞的理論,那么現(xiàn)在就結(jié)合一下程序來分析一下。=發(fā)送方(本例是用服務(wù)端做發(fā)送方的)=procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);vars, sCommand: string;fStream : TFileStream; /定義一個文件流FFileName:string;aSize:in

15、teger;Buf : array0.1023 of Byte; /創(chuàng)建1M的內(nèi)存緩沖區(qū)ReadCount: integer;beginFFileName:='test.rar' ; /我們約定就發(fā)送的文件名是 test.rartrys := uppercase(AThread.Connection.ReadLn); /接受客戶端發(fā)過來的一個字符串sCommand := copy(s,1,3); /取這個字串的前3位if sCommand = 'GET' then /如果前3位字串是 “GET” 就發(fā)文件Beginmemo1.Lines.Add('接到指

16、令 GET ,開始相應(yīng)工作') ;fstream:=tfilestream.Create(ExtractFileDir(ParamStr(0) +''+FFileName,fmOpenRead+ fmShareDenyNone); /針對 test.rar創(chuàng)建文件流AThread.Connection.WriteLn(ExtractFileName(FFileName);AThread.Connection.ReadLn(#13#10, 1000) ;/這兩行作用是把文件名發(fā)送過去,ReadLn(#13#10, 1000) ;我目前也沒搞清是做什么用的,但是對方要用得到

17、的,不能去掉的aSize:= fstream.Size; /從文件流中獲取本地文件大小AThread.Connection.WriteBuffer(aSize, 4); /把這個大小數(shù)值傳過去while fstream.Position < fstream.Size do/用一個循環(huán)來設(shè)定將文件一塊一塊放到要傳輸?shù)臄?shù)據(jù)流中begin/以下這塊是判斷每次讀寫到從文件流里讀入緩存區(qū)的大小if fstream.Size - fstream.Position >= SizeOf(Buf) thenReadCount := sizeOf(Buf)else ReadCount := fstre

18、am.Size - fstream.Position;fstream.ReadBuffer(Buf, ReadCount); /從文件流中讀取數(shù)據(jù),放到緩存區(qū)AThread.Connection.WriteBuffer(Buf, ReadCount);/從緩存區(qū)把數(shù)據(jù)發(fā)到數(shù)據(jù)流中memo1.Lines.Add('寫文件 '+inttostr(ReadCount)+' 字節(jié) ') ;end;AThread.Connection.ReadLn; /這句作用不大,好像可以去掉的AThread.Connection.CloseWriteBuffer; /關(guān)閉傳輸數(shù)據(jù)流m

19、emo1.Lines.Add('關(guān)閉客戶端文件流可寫緩沖區(qū) ') ;/釋放資源FreeAndNil(fStream);memo1.Lines.Add('釋放資源 ') ;EndfinallyAThread.Connection.Disconnect;memo1.Lines.Add('斷開本次連接 ') ;end;end;=接受方(本例是用客戶端做接受方的)=客戶端 要發(fā)送一個約定好的指令給服務(wù)端,然后服務(wù)端給它傳輸文件test.rarprocedure TForm1.Button1Click(Sender: TObject);varaFileNa

20、me:string;ftmpStream : TFileStream; /定義一個文件流aFileSize:integer;ReadCount:integer;Buff: array0.1023 of Byte; /定義一個緩存區(qū)beginwith IdTCPClient1 dobegintryconnect; /連接服務(wù)端if connected thenbeginwriteln('GET'); /發(fā)送 GET指令memo1.Lines.Add('GET指令已經(jīng)發(fā)送');aFileName := IdTCPClient1.ReadLn(#13#10, 100)

21、 ; /讀取傳輸過來的文件名if aFileName = '' then Exit;/如果已經(jīng)存在這個文件,先刪掉if FileExists(ExtractFileDir(ParamStr(0) + ''+aFileName) thenbeginmemo1.Lines.Add('本地目錄存在'+aFileName+',刪掉這個文件');DeleteFile(ExtractFileDir(ParamStr(0) + ''+aFileName);end;/讀取傳輸過來的文件名IdTCPClient1.WriteLn;I

22、dTCPClient1.ReadBuffer(aFileSize, 4); /讀取文件大小ProgressBar1.Max := aFileSize; /設(shè)置進(jìn)度條的顯示最大數(shù)字/創(chuàng)建文件流ftmpStream:= TFileStream.Create(ExtractFileDir(ParamStr(0) +''+aFileName, fmCreate);/用一個循環(huán),不停讀取數(shù)據(jù)流 然后利用文件流寫入文件中repeat/確定本次循環(huán)讀取的快數(shù)大小if aFileSize - ftmpStream.Size > SizeOf(Buff) thenReadCount :=

23、SizeOf(Buff)elseReadCount := aFileSize - ftmpStream.Size;IdTCPClient1.ReadBuffer(Buff, ReadCount); /將傳來的數(shù)據(jù)流讀入緩存區(qū)ftmpStream.WriteBuffer(Buff, ReadCount); /將緩存區(qū)的數(shù)據(jù)寫進(jìn)文件中memo1.Lines.Add('寫入文件 '+inttostr(ReadCount)+'字節(jié)。');ProgressBar1.Position := ftmpStream.Size; /改變進(jìn)度條的狀態(tài)Application.Proc

24、essMessages;until ftmpStream.Size >= aFileSize;memo1.Lines.Add('讀取連接流中數(shù)據(jù),寫入創(chuàng)建的文件流對象ftmpStream中。');disconnect;memo1.Lines.Add('斷開本次連接');end;finallyFreeAndNil(fTmpStream);memo1.Lines.Add('釋放文件流對象ftmpStream占用的資源。');end;end;end;好了 至此,整個流程以及核心代碼已經(jīng)介紹完了,不知道你是否有所收獲?附: 源碼客戶端:unit c

25、lient;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,IdTCPClient, ComCtrls;typeTForm1 = class(TForm)    IdTCPClient1: TIdTCPClient;    Memo1: TMemo; &

26、#160;  Button1: TButton;    ProgressBar1: TProgressBar;    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);private     Private declarations public     Publi

27、c declarations end;varForm1: TForm1;implementation$R *.dfmprocedure TForm1.Button1Click(Sender: TObject);varaFileName:string;ftmpStream : TFileStream;aFileSize:integer;ReadCount:integer;Buff: array0.1023 of Byte;begin    with   IdTCPClient1 do   

28、0;begin    try      connect;      if connected then      begin      writeln('GET');      memo1.Lines.Add('GET指令已經(jīng)發(fā)送

29、9;);        aFileName := IdTCPClient1.ReadLn(#13#10, 100) ;        if aFileName = '' then   Exit;        if FileExists(ExtractFileDir(ParamStr(0) + ''

30、;+aFileName) then        begin        memo1.Lines.Add('本地目錄存在'+aFileName+',刪掉這個文件');        DeleteFile(ExtractFileDir(ParamStr(0) + ''+aFileName); 

31、0;      end;        IdTCPClient1.WriteLn;        IdTCPClient1.ReadBuffer(aFileSize, 4);        ProgressBar1.Max := aFileSize;    &

32、#160;   ftmpStream:= TFileStream.Create(ExtractFileDir(ParamStr(0) +''+aFileName, fmCreate);        repeat          if aFileSize - ftmpStream.Size > SizeOf(Buff) then   

33、         ReadCount := SizeOf(Buff)          else            ReadCount := aFileSize - ftmpStream.Size;       &#

34、160;  IdTCPClient1.ReadBuffer(Buff, ReadCount);          ftmpStream.WriteBuffer(Buff, ReadCount);          memo1.Lines.Add('寫入文件 '+inttostr(ReadCount)+'字節(jié)。');  

35、0;       ProgressBar1.Position := ftmpStream.Size;          Application.ProcessMessages;         until ftmpStream.Size >= aFileSize;      

36、;  memo1.Lines.Add('讀取連接流中數(shù)據(jù),寫入創(chuàng)建的文件流對象ftmpStream中。');        disconnect;        memo1.Lines.Add('斷開本次連接');      end;    finally  

37、0;   FreeAndNil(fTmpStream);      memo1.Lines.Add('釋放文件流對象ftmpStream占用的資源。');    end;    end;end;procedure TForm1.FormCreate(Sender: TObject);begin   IdTCPClient1.Host:='' ;&#

38、160;  IdTCPClient1.port:=5555 ;end;end.服務(wù)端unit serverunit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, IdBaseComponent, IdComponent, IdTCPServer,IdSocketHandle,IdResourceStrings,IdStack, IdGlobal,StdCtrls;typeTForm1 = class(TForm) &#

39、160;  Memo1: TMemo;    Button1: TButton;    Button2: TButton;    IdTCPServer1: TIdTCPServer;    procedure IdTCPServer1Execute(AThread: TIdPeerThread);    procedure Button1Click(Sender: TObje

40、ct);    procedure Button2Click(Sender: TObject);    procedure FormCreate(Sender: TObject);private     Private declarations public     Public declarations end;varForm1: TForm1;implementation$R *.dfmprocedure TForm1.IdTCPS

41、erver1Execute(AThread: TIdPeerThread);var    s, sCommand: string;    fStream : TFileStream;    FFileName:string;    aSize:integer;    Buf : array0.1023 of Byte;    ReadCount: integ

42、er;begin    FFileName:='test.rar' ;     try       s := uppercase(AThread.Connection.ReadLn);       sCommand := copy(s,1,3);       if sCommand

43、= 'GET' then         Begin            memo1.Lines.Add('接到指令 GET ,開始相應(yīng)工作') ;            /fstream:=tfilestream.Create(Ext

44、ractFileDir(ParamStr(0) +'key.txt',fmOpenRead + fmShareDenyNone);            /memo1.Lines.Add('創(chuàng)建文件流 ') ;            /AThread.Connection.OpenWriteBuffer;  

45、;          /memo1.Lines.Add('打開客戶端文件流可寫緩沖區(qū) ') ;            /改寫的程序            fstream:=tfilestream.Create(ExtractFileDir(Pa

46、ramStr(0) +''+FFileName,fmOpenRead + fmShareDenyNone);            AThread.Connection.WriteLn(ExtractFileName(FFileName);            AThread.Connection.ReadLn(#13#10, 1000)

47、;            aSize:= fstream.Size;            AThread.Connection.WriteBuffer(aSize, 4);            while fstream.Positio

48、n < fstream.Size do             begin               if fstream.Size - fstream.Position >= SizeOf(Buf) then        

49、          ReadCount := sizeOf(Buf)                 else ReadCount := fstream.Size - fstream.Position;          

50、0;    fstream.ReadBuffer(Buf, ReadCount);               AThread.Connection.WriteBuffer(Buf, ReadCount);               memo1.Lines.

51、Add('寫文件 '+inttostr(ReadCount)+' 字節(jié) ') ;            end;            AThread.Connection.ReadLn;            AThread.Connection.CloseWriteBuffer;            memo1.Lines.Add('關(guān)閉客戶端文件流可寫緩沖區(qū) ') ;            FreeAndNil(fStream);       &

溫馨提示

  • 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

提交評論