3d打印冰激凌:用TTcpClient和TTcpServer进行文件的传输 - [Delphi编程]

来源:百度文库 编辑:中财网 时间:2024/04/29 22:08:17

2010-01-27

用TTcpClient和TTcpServer进行文件的传输 - [Delphi编程]

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://samver.blogbus.com/logs/57192157.html

客户端:

定义了一个常量:

const BLOCK_SIZE = 1024;//把文件分开来传,每一次传送1024个字节

然后在Form上放一个TTcpClient和一个按钮,为按钮的点击写处理过程:

procedure TForm1.Button1Click(Sender: TObject);
var
  sFileFullName, sFileName : string; //带路径的文件名, 文件名
  iFileLen     : LongInt;  //文件大小
  sMsg         : string;  //接收到的消息
  i, cyc       : Integer; //循环传送次数
  FileStem     : TMemoryStream; //文件数据
  PBuf         : Pointer;
  acBlockSize, tmpSize, LastBlockSize : Integer; //实际读取的数据大小 ,从Stream中际读取的大小,最后一个数据块的大小
begin
  if dlgOpen1.Execute then
  begin
    sFileFullName := dlgOpen1.FileName;
  end;
  if sFileFullName = '' then
    Exit;
  sFileName := ExtractFileName(sFileFullName);  //从带路径的文件名中提取文件名
  FileStem := TMemoryStream.Create;
  try
    FileStem.LoadFromFile(sFileFullName);
    iFileLen := FileStem.Size;
    sMsg := sFileName + '^' + IntToStr(iFileLen);   //拼装消息:文件名+^+文件大小
    TcpClient1.RemoteHost := edt1.Text;   //从Edit中取服务器地址
    TcpClient1.RemotePort := '32765';    //要连接的端口
    TcpClient1.Open;     //连接服务器
    if TcpClient1.Connected then
    begin
      with TcpClient1 do
      begin
        Sendln(sMsg);    //发送拼装好的消息
        sMsg := Receiveln(CRLF);
        if iFileLen mod BLOCK_SIZE = 0 then
          cyc := iFileLen div BLOCK_SIZE     //把文件分块进行传输,如果文件大小能被定义好的BLOCK_SIZE整除,就循环iFileLen 除以 BLOCK_SIZE那么多次就行了
        else
          cyc := iFileLen div BLOCK_SIZE + 1; //把文件分块进行传输,如果文件大小不能被定义好的BLOCK_SIZE整除,要多传一次,把剩下的数据块传完
        if sMsg = 'OK' then     //服务器已经准备好,下面开始发送数据
        begin
          GetMem(PBuf,BLOCK_SIZE);  //分配内存
          try
            for i := 1 to cyc do
            begin
              if i = cyc then
              begin
                LastBlockSize := iFileLen - FileStem.Position; //如果已经传到最后一块了,计算好最后一块的大小
                tmpSize := FileStem.Read(PBuf^,LastBlockSize);
                acBlockSize := SendBuf(PBuf^,LastBlockSize);
              end
              else
              begin
                tmpSize := FileStem.Read(PBuf^,BLOCK_SIZE);   //发送正常的数据块
                acBlockSize := SendBuf(PBuf^,BLOCK_SIZE);
              end;  //}
            end;   
          finally
            FreeMem(PBuf);
          end;
        end;
      end;
    end;
    TcpClient1.Close;
  finally
    FileStem.Free;
  end;

end;

 

 

服务器端:

同样也要定义一个常量:

const BLOCK_SIZE = 1024;//把文件分开来传,每一次传送1024个字节

在Form上放一个按钮,Caption为“开始监听”

procedure TForm1.Button1Click(Sender: TObject);
begin
  TcpServer1.LocalPort := '32765';
  TcpServer1.Open;
  Button1.Enabled := False;
end;

在Form上放一个TTcpServer,为它的OnAccept编写事件:

procedure TForm1.TcpServer1Accept(Sender: TObject;
  ClientSocket: TCustomIpClient);
var
  MsgList : TStringList;  //消息列表
  FileStem: TMemoryStream; //文件流
  sFileName : string; //文件名
  iFileLen  : LongInt; //文件大小,最大为2G
  sMsg : string; //接收的消息,用于商量传输过程
  PBuf  : Pointer; //内存块指针
  i, cyc     : Integer; //cyc是计算出来的,一个文件要循环传送多少次
  acBlockSize,tmpSize,LastBlockSize  : Integer; //实际读取的数据大小
begin
  MsgList := TStringList.Create;
  FileStem := TMemoryStream.Create;
  try
    with ClientSocket do
    begin
      sMsg := Receiveln(CRLF);//接收消息
      MsgList.CommaText := StringReplace(sMsg,'^',',',[rfReplaceAll]); //折分消息,如果文件名上有空格,Delphi会把空格也作为分隔符,这好像是Delphi中的一个BUG。
      if MsgList.Count < 2 then
      begin
        Sendln('Error');
        Exit;
      end
      else
      begin

        sFileName := MsgList.Strings[0]; //文件名
        iFileLen := StrToIntDef(MsgList.Strings[1],-1);//文件大小
        if (sFileName = '') or (iFileLen = -1) then
        begin
          ShowMessage('文件大小为负或文件名不全,不接收');
          Exit;
        end
        else
        begin
          if iFileLen mod BLOCK_SIZE = 0 then
            cyc := iFileLen div BLOCK_SIZE  //文件大小能被块大小整除,循环次数就是文件大小除以块大小
          else
            cyc := iFileLen div BLOCK_SIZE + 1; // 文件大小不能被块大小整除,循环次数就是文件大小除以块大小  + 1
          Sendln('OK'); //文件名和文件大小获取成功,发送回执
          GetMem(PBuf,BLOCK_SIZE);
          try
            for i := 1 to cyc do
            begin

              if i = cyc then
                begin
                  LastBlockSize := iFileLen - FileStem.Size;   //最后一块,计算最后一个数据块的大小
                  acBlockSize := ReceiveBuf(PBuf^,LastBlockSize);  //从Socket接收内容
                  tmpSize := FileStem.Write(PBuf^,acBlockSize); //写到memoryStream 中
                end
              else
              begin
                acBlockSize := ReceiveBuf(pbuf^,BLOCK_SIZE);  //接收正常的数据块
                tmpSize := FileStem.Write(PBuf^,BLOCK_SIZE);
              end;       

           end;
          finally
            FreeMem(PBuf);
          end;
          FileStem.Position := 0;
          FileStem.SaveToFile('d:\Tcptmp\' + sFileName);  //保存到硬盘中
        end;
      end;
    end;
  finally
    MsgList.Free;
    FileStem.Free;
  end;
end;