TCP/IP实现局域网文件传送的问题?(50分)

  • 主题发起人 主题发起人 zfs88
  • 开始时间 开始时间
Z

zfs88

Unregistered / Unconfirmed
GUEST, unregistred user!
我做了一个局域网文件传送的程序,方法是:
1、server端首先将文件名及文件大小发送给client端
2、client端收到文件名及文件大小信息后,返回一条信息,如:“Ready”表示已准备好接收
3、server端开始传送文件内容(无其它附加信息,如“引导包”之类),每次传1024 Byte
4、client端收到1024Byte后,再发送一条“ready”信息给server端
5、server端继续传送下面的1024 Byte

如此,你一句我一句地进行,能够正常传送文件。程序实现很简单。
不知这样的做法有没有什么缺陷,还请各位高手不吝赐教。
 
用不着这么烦啦,你做得很多事情是在重复底层协议的事情,只要2步
1、server端首先将文件名及文件大小发送给client端
2、client端收到文件名及文件大小信息后,返回一条信息,如:“Ready”表示已准备好接收
3、server发送文件内容。
 
我开始也是用delphi朋友的方法,但发现当发送一个较大的文件时(>=5MB),客户端就象死了一样,
半天都反应不过来,虽然最终也能完成文件传送。
所以最后还是改为分批发送,每次发送1 ~ 2K 字节,虽然慢一点,但总比原来好。
 
能不能把原理说清楚些,这个也是我想问的问题了[:)][:)]
 
zfs88兄:
能把你写的程序给我一份吗。
gung_@163.com
 
to zfs88:
看着象死机是因为是采用的阻塞方式啦,
如果你用Indy,可以用一下TIdAntiFreeze组件,
如果你用的是其他socket,服务器端一次写,客户端可以分块读,
也没有必要每一块都确认,确认、重发都是TCP协议完成的事情。
 
我将程序贴在此,供大家批评指正。
服务端:
procedure TForm1.FormCreate(Sender: TObject);
begin
//开始侦听客户端的连接请求
ServerSocket1.Open;
//获取IP地址及子网掩码
EnumInterfaces(sIP,sMask);
//设置UDP的广播地址
NMUDP1.RemoteHost:=GetBCIP(sIp,sMask);
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
// OpenDialog1.InitialDir:='d:/game';
if OpenDialog1.Execute then
begin
Edit1.Text:=ExtractFileName(OpenDialog1.FileName);
FileSize:=GetFileSize(OpenDialog1.FileName);
fs:=TFilestream.Create(OpenDialog1.FileName,fmOpenRead);
Button1.Enabled:=true;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
DataStream:TMemoryStream;
begin
DataStream:=TMemoryStream.Create;
//将服务端的IP地址广播出去
DataStream.Write(sIP[1],length(sIP));
//NMUDP1的RemoteHost设为广播地址:192.168.1.255
NMUDP1.SendStream(DataStream);
DataStream.Free;
Button1.Enabled:=false;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
s:string;
i:integer;
begin
s:=OpenDialog1.FileName+'/'+InttoStr(FileSize);
Button2.Enabled:=false;
//首先发送文件名、文件大小信息
for i:=0 to ServerSocket1.socket.ActiveConnections-1 do
ServerSocket1.socket.Connections.sendbuf(s[1],length(s));
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
const DataSize=1024;
var
ReTxt:string;
buff:pointer;
RealCount,i:integer;
begin
ReTxt:=socket.ReceiveText;
if ReTxt='Ready' then
//开始发送文件
begin
getmem(buff,datasize);
//RealCoun为实际读取的字节数
RealCount:=fs.Read(buff^,datasize);
//向所有已建立连接的客户端分批发送文件内容
for i:=0 to ServerSocket1.socket.ActiveConnections-1 do
ServerSocket1.socket.Connections.sendbuf(buff^,RealCount);
freemem(buff,DataSize);
end;
end;

procedure TForm1.NMUDP1DataReceived(Sender: TComponent;
NumberBytes: Integer; FromIP: String);
var
Buff: string;
begin
setlength(Buff,NumberBytes);
NMUDP1.ReadBuffer(Buff[1],NumberBytes);
Memo1.Lines.Add(Buff);
Memo1.Lines.Add('客户端IP :'+FromIP);
Button2.Enabled:=true;
end;

客户端:
var
Form1: TForm1;
FileName:string;
FileSize:integer;
DestFileStream:TFileStream;
FilenfoReceived:Boolean; //表示是否已接收到文件名及文件大小信息

implementation

{$R *.DFM}

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
const datasize=1024;
var RealCount:integer;
FileInfo:string;
Buff:Pointer;
begin
if (not FilenfoReceived) then
begin
FilenfoReceived:=true;
FileInfo:=socket.ReceiveText;
FileName:=copy(FileInfo,1,pos('/',FileInfo)-1); //服务端发送的文件名与文件长度之间有一“/”
Memo1.lines.add('文件名:'+FileName);
FileSize:=StrToInt(copy(FileInfo,pos('/',FileInfo)+1,length(FileInfo)));
Memo1.lines.add('文件大小:'+Inttostr(FileSize)+' Byte');
ClientSocket1.Socket.SendText('Ready');
ProgressBar1.Max:=filesize;
ProgressBar1.Step:=1;
//建立目标文件
DestFileStream:=TFileStream.Create(ExtractFileName(FileName),fmCreate or fmOpenWrite);
end
else
//开始接收文件
begin
getmem(buff,datasize);
RealCount:=ClientSocket1.Socket.ReceiveBuf(Buff^,datasize);
DestFileStream.WriteBuffer(Buff^,RealCount); //将接收到的文件内容写入目标文件
edit1.Text:='已接收:'+inttostr(DestFileStream.size)+'Byte';
ProgressBar1.Position:=DestFileStream.Size;
ClientSocket1.Socket.SendText('Ready'); //返回一条信息,准备接收后续数据
freemem(buff);
if DestFileStream.size>=FileSize then
begin
Memo1.Lines.Add('文件传输完毕!');
DestFileStream.Free;
end;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FilenfoReceived:=false;
end;

procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ClientSocket1.Socket.SendText('连接成功');
end;

procedure TForm1.NMUDP1DataReceived(Sender: TComponent;
NumberBytes: Integer; FromIP: String);
var
MyStream:TMemoryStream;
TmpStr:string;
begin
Memo1.Lines.Add('服务端IP:'+FromIP);
TmpStr:='请发送文件!';
MyStream:=TMemoryStream.Create;
NMUDP1.RemoteHost:=FromIP;
//通知Server端,可以发送文件了
try
MyStream.Write(TmpStr[1],Length(TmpStr)); //将数据写入流中
NMUDP1.SendStream(MyStream);
finally
MyStream.Free;
end;
if ClientSocket1.Active then ClientSocket1.Close;
ClientSocket1.Host:=FromIP;
ClientSocket1.Active:=true;
end;
 
老兄,不用复杂的,请关注我这个问题
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1037706
帮我解决后,我提供源代码给你。
 
接受答案了.
 
后退
顶部