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;