用TTcpClient和TTcpServer进行文件的传输

发送数据时有Sendln,SendBuf,SendStream。接收数据时有Receiveln,ReceiveBuf,当时我很奇怪为什么没有ReceiveStream。因为很自然的想到是对应关系的。但当时我不知道,发数据时是一小段一小段地发的

看看SendStream代码:

[delphi] view plain copy
 
 
  1. function TBaseSocket.SendStream(AStream: TStream): Integer;  
  2. var  
  3.   BufLen: Integer;  
  4.   Buffer: array[0..511] of Byte;  
  5. begin  
  6.   Result := 0;  
  7.   if Assigned(AStream) then  
  8.   begin  
  9.     repeat  
  10.       BufLen := AStream.Read(Buffer, SizeOf(Buffer));  
  11.     until (BufLen = 0) or (SendBuf(Buffer, BufLen) = SOCKET_ERROR);  
  12.   end;  
  13. end;  

从以上代码可看到,SendStream一次最多发送512字节的内容,所以,我们这接收端循环用ReceiveBuf接收就可以了。不用像以前那样写得又复杂乱。

发送端(Client)代码:

[delphi] view plain copy
 
 
  1. unit Unit1;  
  2.   
  3. interface  
  4.   
  5. uses  
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  7.   Dialogs, StdCtrls, Sockets;  
  8.   
  9. type  
  10.   TForm1 = class(TForm)  
  11.     tcpclnt1: TTcpClient;  
  12.     btn1: TButton;  
  13.     procedure btn1Click(Sender: TObject);  
  14.   private  
  15.     { Private declarations }  
  16.   public  
  17.     { Public declarations }  
  18.   end;  
  19.   
  20. var  
  21.   Form1: TForm1;  
  22.   
  23. implementation  
  24.   
  25. {$R *.dfm}  
  26.   
  27. procedure TForm1.btn1Click(Sender: TObject);  
  28. var  
  29.   f : TFileStream;//文件流  
  30.   i : Integer;  
  31.   fn : string;//文件名  
  32. begin  
  33.   {用for循环是实现发送多个文件,如果只是发送一个文件,不用循环}  
  34.   for i := to 11 do  
  35.   begin  
  36.     tcpclnt1.Connect; //连接服务端,我把TTcpClient的BlockMode设为bmBlocking  
  37.     fn := 'a' + IntToStr(i) + '.rar';  
  38.     f := TFileStream.Create('d:/send/' + fn,fmOpenRead); //用文件流以读方式打开要发送的文件  
  39.     tcpclnt1.Sendln(fn); //给对方发送文件名  
  40.     tcpclnt1.Sendln(IntToStr(f.Size)); //给对方发送文件大小  
  41.     tcpclnt1.SendStream(f); //发送文件流  
  42.     f.Free;//释放文件流  
  43.     tcpclnt1.Disconnect;//关闭连接  
  44.   end;  
  45. end;  
  46.   
  47. end.  

接收端(Server)代码:

[delphi] view plain copy
 
 
  1. unit Unit1;  
  2.   
  3. interface  
  4.   
  5. uses  
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  7.   Dialogs, Sockets;  
  8.   
  9. type  
  10.   TForm1 = class(TForm)  
  11.     tcpsrvr1: TTcpServer;  
  12.     procedure FormActivate(Sender: TObject);  
  13.     procedure tcpsrvr1Accept(Sender: TObject;  
  14.       ClientSocket: TCustomIpClient);  
  15.   private  
  16.     { Private declarations }  
  17.   public  
  18.     { Public declarations }  
  19.   end;  
  20.   
  21. var  
  22.   Form1: TForm1;  
  23.   
  24. implementation  
  25.   
  26. {$R *.dfm}  
  27.   
  28. procedure TForm1.FormActivate(Sender: TObject);  
  29. begin  
  30.   tcpsrvr1.Open; //在OnActive事件中启动TCPServer的监听  
  31. end;  
  32.   
  33. procedure TForm1.tcpsrvr1Accept(Sender: TObject;  
  34.   ClientSocket: TCustomIpClient);  
  35. var  
  36.   f : TFileStream;  //文件流  
  37.   iFileSize : Integer; //文件大小  
  38.   iTotalRec : Integer; //总接收到的字节数,用来和文件大小比较,如果比文件大小的值要小,就还要继续接收  
  39.   iacRec    : Integer; //每一次ReceiveBuf实际接收到的字节数  
  40.   pbuf      : Pointer; //缓存指针  
  41.   i : Integer;  
  42.   fn : string; //文件名  
  43. begin  
  44.     GetMem(pbuf,512); //我们一次最多也读取512字节  
  45.     try  
  46.       iTotalRec := 0;   //先把总接收到的字节数置零  
  47.       fn := ClientSocket.Receiveln; //接收文件名  
  48.       iFileSize := StrToInt(ClientSocket.Receiveln); //接收文件大小,接收到的字符串,要转成integer  
  49.       f := TFileStream.Create('d:/rec/'+ fn,fmCreate);//创建文件  
  50.       try  
  51.         {如果接收到的总字节数小于文件总字节数且实际接收字节数不为-1就一直循环接收}  
  52.         while iTotalRec < iFileSize  do  
  53.         begin  
  54.           iacRec := ClientSocket.ReceiveBuf(pbuf^,512);//一次接收512字节  
  55.           if iacRec = -then  
  56.             Break;//如果实际接收字节数是-1表示出错了,退出循环(应该写个log,或作出错处理什么的)  
  57.           f.Write(pbuf^,iacRec);//把接收到的数据写到文件流中  
  58.           Inc(iTotalRec,iacRec);//叠加接收到的总字节数  
  59.         end;  
  60.       finally  
  61.         f.Free; //释放流  
  62.       end;  
  63.     finally  
  64.       FreeMem(pbuf);//释放内存  
  65.     end;  
  66. end;  
  67.   
  68. end.  
http://blog.csdn.net/zang141588761/article/details/52288692
原文地址:https://www.cnblogs.com/findumars/p/6711191.html