一段关于网络传输文件的代码,请各位帮助分析分析。。给高分!!!(200分)

  • 主题发起人 主题发起人 sforever
  • 开始时间 开始时间
给一个源代码你看看吧
ftp://61.152.210.98:20/Socket2.rar
 
我看了以下代码,有些小问题,如果客户端处理一次连接后没有断开、没有对文件的大小精
确判断,文件被大了。同时我是在自己计算机上测试的,如果在internet上肯定要压缩和解
压的。但是能够看得出tassadar对indy有一定研究,让小生长见识。
 
呵呵,我的代码里面的确有错误,
本来用一个ReadStream读取全部数据了,后来为了
在progressbar显示,改成分块读取,但是那个ReadStream忘了删掉
现在代码已经改过了,有兴趣可以再下载。
我对indy只是了解一点而已,很久没玩了,要认真用还是serverSocket和ClientSocket
好一点。
 
楼上的大侠,很感谢你的共享精神,你的代码下载了以后,我研究了(只是在本机器上测试)。感觉效果不错!!
serverSocket和ClientSocket不知道你使用过没有。。我想研究一下这两个控件的文件传输问题。如果你有这方面的代码。并且能让我看的话。我当真是感激不尽了。
我找这样的代码很长时间了。这个问题也大概困绕了我一年多的时间。。。希望得到你的帮助。
 
ftp://61.152.210.98:20/ThreadBlocking.rar
这个是用ThreadBlocking模式传递消息(文本)的例子
其中把memo.lines.text改成文件数据就可以实现传递文件了。
不过这种方法要比indy的复杂一点,要写线程。但是比较好控制,
当然写得差也会造成很多麻烦。
 
indy 的阻塞模式传输要好一些!
 
// 司马华鹏
// 客户端
//------------------------------------------------------------------------------
// 处理文件传输信息
procedure TfrmTransFile.CSocketTransRead(Sender: TObject; Socket: TCustomWinSocket);
const
MaxChunkSize = 8192;
var
strMsg:string;
Buffer:array [0..MaxChunkSize] of byte; // 设置接收缓冲区
BytesReceived,BufLen,Index:integer;
FscrPak :TscrPak;
Idx :integer;
strSourDir :string;
strDestDir :string;
begin
if ftpStatus=fsCommand then
begin
strMsg:=Socket.ReceiveText;
strMsg:=LowerCase(strMsg);
if length(strMsg)<=0 then Exit;

// 服务器指示:发送文件
if strMsg[1]=fp_FileSend then
begin
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','请求得到文件信息',False);
Socket.SendText(fP_FileProperty + #10#13'.'#10#13);
end else
// 服务器指示:文件属性 2(0/1)123*c:/1.bat
if strMsg[1]=fP_FileProperty then
begin
if strMsg[2]='0' then
bFileSend:=True
else
bFileSend:=False;

for index:=3 to Length(strMsg) -1 do
begin
if strMsg[index]='*' then
begin
intFileSize:=strToInt(Copy(strMsg,3,index-3));

//如果为文件传输则传输为文件的路径,否则为最终目录
strFileName:=Copy(strMsg,Index+1,Length(strMsg));

if BFileSend then // 传送最终文件
begin
if not DirectoryExists(ExtractFilePath(strFileName)) then
begin
if not ForceDirectories(ExtractFilePath(strFileName)) then
begin
Socket.SendText(fP_FileAbort + #10#13'.'#10#13);
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','创建本地文件夹失败!',True);
Exit;
end;
end;
try // 创建本地文件
FileStrm:= TFileStream.Create(strFileName,fmCreate or fmShareDenyNone );
except
on e:exception do
begin
Socket.SendText(fP_FileAbort + #10#13'.'#10#13);
Exit;
end;
end;
end else begin // 传送的文件为临时文件,最终将接压到文件夹
strTempFile:=GetTempFile;
if not DirectoryExists(strFileName) then
begin
if not ForceDirectories(strFileName) then
begin
Socket.SendText(fP_FileAbort + #10#13'.'#10#13);
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','创建本地文件失败!',True);
Exit;
end;
end;
try // 创建本地文件
FileStrm:= TFileStream.Create(strTempFile,fmCreate or fmShareDenyNone );
except
on e:exception do
begin
Socket.SendText(fP_FileAbort + #10#13'.'#10#13);
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','创建本地文件失败!',True);
Exit;
end;
end;
end;

txtFileName.Text:=strFileName;
txtFileSize.Text:=IntToStr(intFileSize);

Break; //退出当前循环
end;
end;

ftpStatus:=fsFileTrans;
Socket.SendText(fp_FileReady + #10#13'.'#10#13);
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','开始接收!',False);
dwBegin:=GetTickCount; // 开始计时

Animate.Active:=True;
end;
end else
if ftpStatus=fsFileTrans then
begin
bufLen:=Socket.ReceiveLength; // 读出包长度
if bufLen>MaxChunkSize then bufLen:=MaxChunkSize; // 检验数据长度
BytesReceived:=Socket.ReceiveBuf(Buffer,bufLen); // 接收数据包并读入缓冲区内
fileStrm.Write(Buffer,BytesReceived); // 追加入流中

txtDataGet.Text:=InttoStr(fileStrm.Size); // 实际接收进度
Gauge.Progress:=Round(fileStrm.Size * 100/intFileSize); // 显示进度条

if FileStrm.Size>=intFileSize then // 如果流长度大于需接收的字节数,则接收完毕
begin
Socket.SendText(fP_FileEnd + #10#13'.'#10#13); // 通知服务器停止发送
dwEnd:=GetTickCount; // 停止计时
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','接收完毕,速度为:' + FormatFloat('#.#',intFileSize/(1.024 *(dwEnd -DwBegin))) + 'K/S',False);
FileStrm.Free;
intFileSize:=0;

Animate.Active:=False;
ftpStatus:=fsCommand; // 标志位

try
if not bFileSend then
begin
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','开始解压文件!',False);
FscrPak :=TscrPak.Create(nil,strTempFile); // 打开临时文件(将子文件接压)
try
if FscrPak.Directory.Count<=0 then Raise Exception.Create('无效的文件!');
Gauge.MaxValue:=FscrPak.Directory.Count-1;
strSourDir:=FscrPak.Header.Content; // 获取原始路径
For idx:=0 to Gauge.MaxValue do
begin
Application.ProcessMessages;
Gauge.Progress:=idx;
strDestDir:=FscrPak.Directory.Items[idx].ItemPath; // 文件的原始路径
Delete(strDestDir,1,Length(strSourDir)); // 删除前面的多余
strDestDir:=strFileName + strDestDir;
if strDestDir[Length(strDestDir)]<>'/' then strDestDir:= strDestDir + '/';
If Not DirectoryExists(strDestDir) then ForceDirectories(strDestDir);
FscrPak.ItemToFile(idx,strDestDir + FscrPak.Directory.Items[idx].ItemName);
end;
finally
FscrPak.Free;
DeleteFile(strTempFile);
end;
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','解压文件完毕!',False);
end;
except
ON e:Exception do
begin
frmMain.TrackOperateLog(Socket.RemoteAddress,'要求传输文件','发生错误:' + e.Message,True);
end;
end;
if Self.Visible then Self.Hide;
end;
end;
end;
 
//司马华鹏
// 服务器端

//------------------------------SocketTrans事件---------------------------------
procedure TFrmMain.SocketTransAccept(Sender: TObject;Socket: TCustomWinSocket);
var
Item: TListItem;
Idx: Integer;
begin
Item := listView.FindCaption(1,Socket.RemoteAddress,False,True,True);
if Item = nil then
begin
with listView.Items.Add do
begin
Caption := Socket.RemoteAddress;
SubItems.Add('在线');
SubItems.Add('等待传输');
end;
end else
begin
with Item do
begin
SubItems[1]:='等待传输';
end;
end;

// 联接成功则删除
Idx := ListFileTrans.IndexOf(Socket.RemoteAddress);
if Idx >= 0 then ListFileTrans.Delete(Idx);
end;

//------------------------------------------------------------------------------
// 文件传输部分登陆成功
procedure TFrmMain.SocketTransClientConnect(Sender: TObject;Socket: TCustomWinSocket);
var
Item: TListItem;
begin
Item := listView.FindCaption(1,Socket.RemoteAddress,False,True,True);
if Item = nil then
begin
with listView.Items.Add do
begin
Caption := Socket.RemoteAddress;
SubItems.Add('在线');
SubItems.Add('等待传输');
end;
end else
begin
with Item do
begin
SubItems[1]:='等待传输';
end;
end;
end;

//------------------------------------------------------------------------------
procedure TFrmMain.SocketTransClientDisconnect(Sender: TObject;Socket: TCustomWinSocket);
var
Item:TListItem;
begin
//找到地址相同的机器,然后修改其传输状态
Item := listView.FindCaption(1,Socket.RemoteAddress,False,True,True);
if Item <> nil then
begin // 如果找到
with Item do
begin
SubItems[1] := '结束传输'; // 显示传输状态
end;
end;
end;

//------------------------------------------------------------------------------
procedure TFrmMain.SocketTransClientError(Sender: TObject;Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent;var ErrorCode: Integer);
var
Item:TListItem;
begin
//找到地址相同的机器,然后修改其传输状态
Item := listView.FindCaption(1,Socket.RemoteAddress,False,True,True);
if Item <> nil then
begin // 如果找到
with Item do
begin
SubItems[1] := '传输结束,网络故障:' + fcTransNetErrString(ErrorCode);
end;
end;

ErrorCode := 0;
end;

{ TDbServerThread }
//------------------------------------------------------------------------------
// 文件传输执行线程
procedure TDbServerThread.ClientExecute;
var
Stream: TWinSocketStream;
Buffer, strIn: string;
nRead: Integer;
nFileSize:integer;
Item:TListItem;
begin
inherited FreeOnTerminate := TRUE; // 关闭后自动释放
Stream := TWinSocketStream.Create(ClientSocket, 6000); // 6000为超时限制时间
try
while not Terminated and ClientSocket.Connected do
begin // 初始化,读取消息
Buffer := '';
strIn := '';
SetLength(Buffer, 64);
repeat
nRead := Stream.Read(Buffer[1], 64);
if nRead = 0 then
begin
ClientSocket.Close;
Break;
end;
SetLength (Buffer, nRead);
StrIn := StrIn + Buffer;
until (Pos(#10#13'.'#10#13, Buffer) > 0);

if strIn = '' then // 没有请求
Continue // 继续循环
else begin // 处理请求
StrCommand := Copy (strIn, 1, Pos (#10#13'.'#10#13, strIn) -1);

Case StrCommand[1] of
fp_FileProperty:
begin {1} // 客户要求得到文件属性
Item:=frmMain.ListView.FindCaption(1,ClientSocket.RemoteAddress,False,True,True);
if Item<>nil then
begin
Item.SubItems[1]:='请求文件信息'; // 显示传输状态
end;

nFileSize:=fcGetFileSize(strSourceFile);

if bSendFile then
strFeedback:= fp_FileProperty + '0' + Inttostr(nFileSize) + '*' + strDestFile
else
strFeedback:= fp_FileProperty + '1' + Inttostr(nFileSize) + '*' + strDestFile;

Stream.Write(strFeedback[1], Length (strFeedback)); //应答
end;
fp_FileReady:
begin {2} // 客户准备完毕,可以发送
Item:=frmMain.ListView.FindCaption(1,ClientSocket.RemoteAddress,False,True,True);
if Item<>nil then
begin
Item.SubItems[1]:='正在接收...';
end;

ClientSocket.SendStream(TFileStream.Create(strSourceFile, fmOpenRead or fmShareDenyNone));
end;
fP_FileEnd:
begin {3} // 客户接收完毕,检测完成状态
Item:=frmMain.ListView.FindCaption(1,ClientSocket.RemoteAddress,False,True,True);
if Item<>nil then
begin
Item.SubItems[1]:='接收完毕';
end;

ClientSocket.Close;
Terminate;
end;

fP_FileABORT:
begin {4} // 客户要求中断传输
Item:=frmMain.ListView.FindCaption(1,ClientSocket.RemoteAddress,False,True,True);
if Item<>nil then
begin
Item.SubItems[1]:='传输因意外中断';
end;

ClientSocket.Close;
Terminate;
end;
end;
end;
end; // 在循环中获取消息
finally
Stream.Free;
end;
end;

//------------------------------------------------------------------------------
// 接收文件线程创建
procedure TFrmMain.SocketTransGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
ClientSocket.SendText(fP_FileSend); //发送一个文件发送信号
SocketThread := TDbServerThread.Create(False, ClientSocket);
end;
 
上面是我的一个项目中的代码,有些乱,呵呵

没有分块,是多线程传输的,在无忌兄面前班门弄斧了,呵呵
 
RE:爱元元的哥哥
久仰大名,如雷阵耳。。总是在大富翁上搜索你的帖子。。。。但是很少发言。
不知道有没有只使用ClientSocket 和serversocket的文件传输代码??
我想看看这个是怎么传输的!!
 
后退
顶部