网络文件传输问题

ttily77 2006-01-10 04:57:44
各位高人,请帮帮忙:
我想通过客户端传图片给服务器(一次大概,60张左右,大小一共大概30M左右),客户端也可以读回服务器上的图片(也即是把服务器上的图片写到客户端本地)。
可以多个客户端同时操作。请问:客户端,服务器端,怎么做,希望能给出一点源码。谢谢,如果分不够可以加。
...全文
248 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
clasj 2006-01-12
  • 打赏
  • 举报
回复
把Indy带的那个Ftp客户端和服务端Demo稍微改一下,绝对够你用了。
shycoffee 2006-01-11
  • 打赏
  • 举报
回复
不知道具体的环境,做这样的假设:如果是局域网,而且传输的文件量较大,对性能要求的高,建议用INDY里面的两组控件TCP和UDP服务器客户端.(下面有源码)
如果是广域网环境可以用INTERNET里面的TClientSocket和TServerSocket.在DEMO里面有例子.
ttily77 2006-01-11
  • 打赏
  • 举报
回复
谢谢各位,现在只考虑局域网内,但要求速度不能太慢,连接也要稳定,不要因为和序出现连接失败的现象
shycoffee 2006-01-11
  • 打赏
  • 举报
回复
服务器端:
unit U_Server;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, IdBaseComponent, IdComponent, IdTCPServer, Math,
IdUDPBase, IdUDPServer, IdSocketHandle;

const
mtFUDPDirReq = 8000;
mtFUDPDirACK = 9000;
mtFUDPReq = 8001;
mtFUDPACK = 9001;
mtFUDPDataReq = 8002;
mtFUDPDataACK = 9002;

type
rMsgHead = record
MsgType: integer;
Userid : array[0..20] of Char;
DataSize: WORD;//0~65535
end;

rFUDPReq = record
ReqType: BYTE;//setup: 1/ stop: 2/ finish: 3
end;

rFUDPACK = record
lResult: BYTE;//ack: 1/ unknown: 0
FileName: array[0..64] of char;
FileSize: integer;
end;

rFUDPDataReq = record
FUDPId: WORD;
FileName: array[0..64] of char;
StartPos: integer;
Length: WORD;
end;

rFUDPDataACK = record
FUDPId: WORD;
Length: WORD;
PieceBuf: array[0..1024] of char;
end;

rFUDPReqBag = record
Head: rMsgHead;
Data: rFUDPReq;
end;

rFUDPACKBag = record
Head: rMsgHead;
Data: rFUDPACK;
end;

rFUDPDataReqBag = record
Head: rMsgHead;
Data: rFUDPDataReq;
end;

rFUDPDataACKBag = record
Head: rMsgHead;
Data: rFUDPDataACK;
end;

Tfrm_Server = class(TForm)
IdTCPServer1: TIdTCPServer;
Button1: TButton;
Button2: TButton;
Button3: TButton;
ProgressBar1: TProgressBar;
StatusBar1: TStatusBar;
Edit1: TEdit;
Button4: TButton;
OpenDialog1: TOpenDialog;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
ClientUDP: TIdUDPServer;
procedure Button1Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure ClientUDPUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
private{ Private declarations }
AFileStream: TFileStream; //传输的文件流
procedure ButtonBegin;
procedure ButtonEnd;
public { Public declarations }
end;

var
frm_Server: Tfrm_Server;

implementation{$R *.dfm}

procedure Tfrm_Server.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
Edit1.Text := OpenDialog1.FileName;
if not FileExists(Edit1.Text) then begin//检测文件是否存在
Showmessage('文件不存在,请选择文件!');
exit;
end;
//建立文件流
AFileStream := TFileStream.Create(Edit1.Text, fmOpenRead);
ProgressBar1.Max := AFileStream.Size;
ProgressBar1.Position := 0;
ButtonBegin; //VCL开始状态设置
end;

procedure Tfrm_Server.Button4Click(Sender: TObject);
begin
Close;
end;

procedure Tfrm_Server.Button2Click(Sender: TObject);
begin
//服务器准备好连接
// IdTCPServer1.DefaultPort := StrToIntDef(Edit2.Text, 9925);
// if not IdTCPServer1.Active then IdTCPServer1.Active := True;
end;

procedure Tfrm_Server.ButtonBegin;
begin //VCL开始状态设置
Button1.Enabled := False;
Button2.Enabled := False;
Button3.Enabled := True;
Button4.Enabled := False;
end;

procedure Tfrm_Server.ButtonEnd;
begin //VCL结束状态设置
Button1.Enabled := True;
Button2.Enabled := True;
Button3.Enabled := False;
Button4.Enabled := True;
end;

procedure Tfrm_Server.Button3Click(Sender: TObject);
begin
StatusBar1.SimpleText := '传输取消...';
AFileStream.Free; //释放文件流
ButtonEnd; //VCL结束状态设置
end;

procedure Tfrm_Server.IdTCPServer1Execute(AThread: TIdPeerThread);
var
cmd: string; //接收到客户端的字符串信息
ASize: Integer; //需要传输的流大小
begin
with AThread.Connection do begin//已经连街上的一个进程
cmd := UpperCase(ReadLn); //客户端发送的命令字符串
if cmd = 'BEGIN' then begin//开始传输
//告诉远程传输文件的大小和文件名
WriteLn(Format('%d|%s', [AFileStream.Size, ExtractFileName(Edit1.Text)]));
StatusBar1.SimpleText := '准备传输...';
Exit;
end;
if cmd = 'END' then begin //传输完成
Button3.Click;
StatusBar1.SimpleText := '传输完成...';
Exit;
end;
if cmd = 'CANCEL' then begin //传输取消
StatusBar1.SimpleText := '传输取消...';
//保持传输状态
Exit;
end;
//按照指定位置传输文件
AFileStream.Seek(StrToInT(cmd), soFromBeginning); //转到文件流传输的位置
ASize := Min(AFileStream.Size - AFileStream.Position, RecvBufferSize);
//计算需要发送的大小,Min()函数在Math单元
OpenWriteBuffer; //准备发送缓冲
WriteStream(AFileStream, false, false, ASize);
//注意这个函数的参数。
CloseWriteBuffer; //结束发送缓冲
StatusBar1.SimpleText := Format('当前传输位置%s/大小%d', [cmd, AFileStream.Size]);
ProgressBar1.Position := ProgressBar1.Position + ASize;
end;
end;

procedure Tfrm_Server.FormClose(Sender: TObject; var Action: TCloseAction);
begin
IdTCPServer1.Active := False;
end;

procedure Tfrm_Server.FormCreate(Sender: TObject);
begin
try
ClientUDP.DefaultPort:=6062;
ClientUDP.Active :=true;
StatusBar1.SimpleText := Format('运行端口:[%d]', [6062]);
except
on EIdCouldNotBindSocket do begin
StatusBar1.SimpleText := '侦听失败!';
end;
end;
end;

procedure Tfrm_Server.ClientUDPUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
_UDPHead: rMsgHead;
_FUDPReq: rFUDPReq;
FUDPACK: rFUDPACKBag;
_FUDPDataReq: rFUDPDataReq;
FUDPDataACK: rFUDPDataACKBag;
MsgType:integer;
// ASize: Integer; //需要传输的流大小
begin
try
AData.Read (_UDPHead,sizeof(_UDPHead) ); //接收数据头
MsgType:=_UDPHead.MsgType;
if Msgtype=-1 then exit;
case MsgType of
mtFUDPReq : begin
Adata.Read(_FUDPReq, SizeOf(rFUDPReq));
case _FUDPReq.ReqType of
1: begin
FUDPACK.Head.MsgType:=mtFUDPACK;
StrPCopy(FUDPACK.Head.Userid, '');
FUDPACK.Head.DataSize:=0;
FUDPACK.Data.lResult:=1;
StrPCopy(FUDPACK.Data.FileName, ExtractFileName(Edit1.Text));
FUDPACK.Data.FileSize:=AFileStream.Size;
ClientUDP.SendBuffer('127.0.0.1', 6061, FUDPACK, SizeOf(rFUDPACKBag));
end;

2: begin
end;

3: begin
Button3.Click;
StatusBar1.SimpleText := 'File transfer finished...';
end;
end;
end;

mtFUDPDataReq: begin
Adata.Read(_FUDPDataReq, SizeOf(rFUDPDataReq));
//按照指定位置传输文件
AFileStream.Seek(_FUDPDataReq.StartPos, 0); //转到文件流传输的位置
//ASize := Min(AFileStream.Size - AFileStream.Position, 256);
//计算需要发送的大小,Min()函数在Math单元
FUDPDataACK.Head.MsgType:=mtFUDPDataACK;
StrPCopy(FUDPDataACK.Head.Userid, '');
FUDPDataACK.Head.DataSize:=0;
FUDPDataACK.Data.FUDPId:=_FUDPDataReq.FUDPId;
FUDPDataACK.Data.Length:=_FUDPDataReq.Length;
AFileStream.ReadBuffer(FUDPDataACK.Data.PieceBuf, _FUDPDataReq.Length);
try
ClientUDP.SendBuffer('127.0.0.1', 6061, FUDPDataACK, SizeOf(rFUDPDataACKBag));
except
ShowMessage('Error in read file to buffer');
end;
StatusBar1.SimpleText := Format('Current transfer position: %d/size: %d', [_FUDPDataReq.StartPos, AFileStream.Size]);
ProgressBar1.Position := ProgressBar1.Position + _FUDPDataReq.Length;
end;
end;
except on E:Exception do
ShowMessage(E.Message);
end;
end;

end.

(源码来自网上)
shycoffee 2006-01-11
  • 打赏
  • 举报
回复
这里用TCP控件建立和维护连接,连接后实际上是用UDP传输文件,所以速度较快.



客户端;

unit U_Client;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, Math,
StdCtrls, ComCtrls, IdUDPBase, IdUDPServer, IdSocketHandle;

const
mtFUDPDirReq = 8000;
mtFUDPDirACK = 9000;
mtFUDPReq = 8001;
mtFUDPACK = 9001;
mtFUDPDataReq = 8002;
mtFUDPDataACK = 9002;

type
rMsgHead = record
MsgType: integer;
Userid : array[0..20] of Char;
DataSize: WORD;//0~65535
end;

rFUDPReq = record
ReqType: BYTE;//setup: 1/ stop: 2/ finish: 3
end;

rFUDPACK = record
lResult: BYTE;//ack: 1/ unknown: 0
FileName: array[0..64] of char;
FileSize: integer;
end;

rFUDPDataReq = record
FUDPId: WORD;
FileName: array[0..64] of char;
StartPos: integer;
Length: WORD;
end;

rFUDPDataACK = record
FUDPId: WORD;
Length: WORD;
PieceBuf: array[0..1024] of char;
end;

rFUDPReqBag = record
Head: rMsgHead;
Data: rFUDPReq;
end;

rFUDPACKBag = record
Head: rMsgHead;
Data: rFUDPACK;
end;

rFUDPDataReqBag = record
Head: rMsgHead;
Data: rFUDPDataReq;
end;

rFUDPDataACKBag = record
Head: rMsgHead;
Data: rFUDPDataACK;
end;

Tfrm_Client = class(TForm)
SaveDialog1: TSaveDialog;
IdTCPClient1: TIdTCPClient;
Button1: TButton;
StatusBar1: TStatusBar;
Edit1: TEdit;
Label1: TLabel;
Edit2: TEdit;
Label2: TLabel;
ClientUDP: TIdUDPServer;
// procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure ClientUDPUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
private { Private declarations }
public { Public declarations }
end;

var
frm_Client: Tfrm_Client;
ASize, TotalSize: integer;
AFileStream: TFileStream;
RecvBit: BYTE;

implementation{$R *.dfm}

{procedure Tfrm_Client.Button1Click(Sender: TObject);
var
cmd: string;
ASize, TotalSize: Int64;
AFileStream: TFileStream;
begin
IdTCPClient1.Host := Edit1.Text; //连接主机
IdTCPClient1.Port := StrToIntDef(Edit2.Text, 9925); //端口
IdTCPClient1.Connect; //连接
try
IdTCPClient1.WriteLn('BEGIN'); //提示服务器开始接收
cmd := IdTCPClient1.ReadLn;
//以“|”符号分离文件名
SaveDialog1.FileName := Copy(cmd, Pos('|', cmd) + 1, Length(cmd));
if not SaveDialog1.Execute then begin
IdTCPClient1.WriteLn('CANCEL'); //告诉服务器取消
IdTCPClient1.Disconnect; //断开连接
exit;
end;
TotalSize := StrToInt(Copy(cmd, 0, Pos('|', cmd) - 1)); //分离文件大小
//建立文件流准备接收
AFileStream := TFileStream.Create(SaveDialog1.FileName, fmCreate);
try //循环开始接受
repeat
IdTCPClient1.WriteLn(IntToStr(AFileStream.Size));//发送当前传输的位置
ASize := Min(TotalSize - AFileStream.Size, IdTCPClient1.RecvBufferSize);
//选择剩余大小和缓冲区大小小的一个作为传输的大小
IdTCPClient1.ReadStream(AFileStream, ASize); //接收流
StatusBar1.SimpleText := Format('当前传输位置%d/大小%d', [AFileStream.Size, TotalSize]);
Application.ProcessMessages;
until AFileStream.Size = TotalSize; //大小一致了表示结束
finally
AFileStream.Free; //释放文件流
end;
IdTCPClient1.WriteLn('END'); //提示服务器传输完成
StatusBar1.SimpleText := '传输完成...';
except
StatusBar1.SimpleText := '连接服务器失败或者对方已经中断传输!';
end;
IdTCPClient1.Disconnect;
end;}

procedure Tfrm_Client.FormCreate(Sender: TObject);
begin
try
ClientUDP.DefaultPort:=6061;
ClientUDP.Active :=true;
StatusBar1.SimpleText := Format('运行端口:[%d]', [6061]);
except
on EIdCouldNotBindSocket do begin
StatusBar1.SimpleText := '侦听失败!';
end;
end;
end;

procedure Tfrm_Client.Button1Click(Sender: TObject);
var
FUDPReq: rFUDPReqBag;
begin
FUDPReq.Head.MsgType:=mtFUDPReq;
StrPCopy(FUDPReq.Head.Userid, '');
FUDPReq.Head.DataSize:=0;
FUDPReq.Data.ReqType:=1;
ClientUDP.SendBuffer('127.0.0.1', 6062, FUDPReq, SizeOf(rFUDPReqBag));
AFileStream:=nil;
ASize:=0;
end;

procedure Tfrm_Client.ClientUDPUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
_UDPHead: rMsgHead;
_FUDPACK: rFUDPACK;
_FUDPDataACK: rFUDPDataACK;
FUDPDataReq: rFUDPDataReqBag;
FUDPReq: rFUDPReqBag;
MsgType:integer;
begin
try
AData.Read (_UDPHead,sizeof(_UDPHead) ); //接收数据头
MsgType:=_UDPHead.MsgType;
if Msgtype=-1 then exit;
case MsgType of
mtFUDPACK : begin
Adata.Read(_FUDPACK, SizeOf(rFUDPACK));
SaveDialog1.FileName := _FUDPACK.FileName;
if not SaveDialog1.Execute then begin
ShowMessage('This operation cancels the file download.');
end;
TotalSize := _FUDPACK.FileSize;
AFileStream := TFileStream.Create(SaveDialog1.FileName, fmCreate);
ASize:=0;
try //循环开始接受
Application.ProcessMessages;
FUDPDataReq.Head.MsgType:=mtFUDPDataReq;
StrPCopy(FUDPDataReq.Head.Userid, '');
FUDPDataReq.Head.DataSize:=0;
FUDPDataReq.Data.FUDPId:=mtFUDPDataReq;
StrPCopy(FUDPDataReq.Data.FileName, _FUDPACK.FileName);
FUDPDataReq.Data.StartPos:=ASize;
FUDPDataReq.Data.Length:=Min(1024, TotalSize-ASize);
StatusBar1.SimpleText := Format('Current transfer position: %d/Size: %d', [ASize, TotalSize]);
ClientUDP.SendBuffer('127.0.0.1', 6062, FUDPDataReq, SizeOf(rFUDPDataReqBag));
except
AFileStream.Free; //释放文件流
end;
end;

mtFUDPDataACK: begin
Adata.Read(_FUDPDataACK, SizeOf(rFUDPDataACK));
if AFileStream<>nil then begin
AFileStream.Position:=ASize;
AFileStream.WriteBuffer(_FUDPDataACK.PieceBuf, _FUDPDataACK.Length);
ASize:=ASize+_FUDPDataACK.Length;
if ASize<TotalSize then begin
try //循环开始接受
Application.ProcessMessages;
FUDPDataReq.Head.MsgType:=mtFUDPDataReq;
StrPCopy(FUDPDataReq.Head.Userid, '');
FUDPDataReq.Head.DataSize:=0;
FUDPDataReq.Data.FUDPId:=mtFUDPDataReq;
StrPCopy(FUDPDataReq.Data.FileName, _FUDPACK.FileName);
FUDPDataReq.Data.StartPos:=ASize;
FUDPDataReq.Data.Length:=Min(1024, TotalSize-ASize);
StatusBar1.SimpleText := Format('Current transfer position: %d/Size: %d', [ASize, TotalSize]);
ClientUDP.SendBuffer('127.0.0.1', 6062, FUDPDataReq, SizeOf(rFUDPDataReqBag));
except
AFileStream.Free; //释放文件流
end;
end else begin
FUDPReq.Head.MsgType:=mtFUDPReq;
StrPCopy(FUDPReq.Head.Userid, '');
FUDPReq.Head.DataSize:=0;
FUDPReq.Data.ReqType:=3;
ClientUDP.SendBuffer('127.0.0.1', 6062, FUDPReq, SizeOf(rFUDPReqBag));
StatusBar1.SimpleText := 'File transfer finished...';
AFileStream.Free; //释放文件流
end;
end;
end;
end;
except on E:Exception do
ShowMessage(E.Message);
end;
end;

end.

aiirii 2006-01-10
  • 打赏
  • 举报
回复
>>客户端传图片给服务器
有没有什么其它要求?? 什么的服务端?
如果这样,indy 控件里面的demo应该有个已经满足你的要求了
yinxu 2006-01-10
  • 打赏
  • 举报
回复
做FTP嘛.很好的啊!

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧