用socket实现ftp客户端连接unix的问题(200分)

  • 主题发起人 主题发起人 freefirez
  • 开始时间 开始时间
F

freefirez

Unregistered / Unconfirmed
GUEST, unregistred user!
server为unix下c编写。模拟ftp命令,上传和下载的均为纯文本文件(<1MB)。
问题是:
1.我要与其协议一个包结构,以便于接受和发送,包内一次发送多大数据合适;
2.如何拆分文件到包;
3.如何获取server端的目录文件,并显示;
4.上传、下载文件时,如何控制。

希望不吝解答。
时间紧任务重,如有例程源码,愿加分。
 
没人回答。
估计是太简单列。
现在我只想知道,如何获取如何获取server端的目录文件,并显示。
 
www.source520.com 再次更新近3万代码,全部免费免注册狂下载
 
Indy的组件可能有,你看看,他用标准的FTP协议做的。
//这个是取目录
procedure TIdFTP.List(ADest: TStrings; const ASpecifier: string = ''; {Do not translate}
const ADetails: boolean = true);
var
LDest: TStringStream;
begin
LDest := TStringStream.Create(''); try {Do not translate}
if ADetails then begin
InternalGet(trim('LIST ' + ASpecifier), LDest); {Do not translate}
end else begin
InternalGet(trim('NLST ' + ASpecifier), LDest); {Do not trnalstate}
end;
FreeAndNil(FDirectoryListing);
if Assigned(ADest) then begin //APR: User can use ListResult and DirectoryListing
ADest.Text := LDest.DataString;
end;
FListResult.Text := LDest.DataString;
finally FreeAndNil(LDest); end;
end;

TIdFTPListItems这个是分析目录的。
 
我只使用socket标准控件实现。
用indy的话,我的其他都要重写了。
 
你先看看FTP协议。
1.按照标准FTP协议,不需要另外定义结构。
2.如果不定结构,也就不再需要拆分文件。
如果是拆分文件,无疑就是将文件一块块的分开放到结构里面发。
用流,API都行。
type
//数据类型 字符串  下载文件 上传文件 记录
TDataType = (dtString, dtGetFile, dtUpFile, dtRecord);

//发送数据记录
TSendData = packed record
FDataType: TDataType; // 数据类型
FSockFlage: Integer; // Server/Client Flage
FDataSize: Integer; // 数据大小
CmdStr: array[1..255] of Char;// COMMAND string
FData: array[1..1024] of Char;// 数据
end;
//API发送文件
//只做参考
procedure SendFile(const S: TSocket; var BufData: TSendData);
var
HF: HFILE;
Len, Size, Offset: Integer;
begin
//打开文件
HF := OpenFile(BufData.CmdStr);
//偏移位置
Offset := 0;
//文件大小
Size := GetFileSize(HF, nil);
if Size <= 0 then begin
//格式文件总数
BufData.FDataSize := 0;
BufData.FData := '文件不存在,或文件为空值';
WinSock.send(S, BufData, SizeOf(TSendData), 0);
Exit;
end;
repeat
//设置读取偏移位
SetFilePointer(HF, Offset, nil, FILE_CURRENT);
//填充BufData.FData
FillChar(BufData.FData, SizeOf(BufData.FData), #0);
//读取文件到Buf
Len := ReadFileBuffer(HF, BufData.FData, SizeOf(BufData.FData));
//数据长度
BufData.FDataSize := Len;
//累加偏移量
Offset := Offset + Len;
//复位文件
SetFilePointer(HF, 0, nil, FILE_BEGIN);
//发送数据
WinSock.send(S, BufData, SizeOf(TSendData), 0);
until Offset >= Size;
CloseFile(HF);
//格式文件总数
BufData.FDataSize := 0;
FillChar(BufData.FData, SizeOf(BufData.FData), #0);
FormatChar(BufData.FData, '文件大小:%d Byte', [Size]);
WinSock.send(S, BufData, SizeOf(TSendData), 0);
end;

var
HF: HFILE = HFILE_ERROR;
procedure ReadFile(const tempFileName: PChar; const ReadBuf: TSendData; const S: TSocket; H: HWND);
var
StatusText: array[0..1024] of Char;
begin
//读取数据Buffer
if ReadBuf.FDataSize > 0 then begin
if HF = HFILE_ERROR then
HF := CreateFile(tempFileName);
SetFilePointer(HF, 0, nil, FILE_END);
Windows._lwrite(HF, ReadBuf.FData, ReadBuf.FDataSize);
end
else //
begin
//写入到硬盘
CloseFile(HF);
if ReadBuf.FData[0] = #0 then Exit;
FormatChar(StatusText, 'Server Host: [%s], ReadBuf.FData: [%s]',
[Integer(GetRemoteHost(S)), Integer(@ReadBuf.FData)]);
MemoAdd(H, StatusText);
end;
end;
 
3.上面的有了。
4.Socket最好是用阻塞模式传输文件,可以看看delphi中的Socket。
 
我定义了
TMark=(C,E);
TCommand=(PASS,QUIT,PUTF,GETF,RPWD,RDIR,RNAM,LIST);
TsendData=packed record
Mark:TMark;
Cmd:TCommand;
len:Integer;
fdata:array[0..1023] of char;
end;
...
var s:TSendData
s内变量都赋值后,我用socket.sendbuf(s,sizeof(s))发送,用socket.sendbuf接收后写入文件,发现s.Mark和s.Cmd没有值。
1.这是为什么?
2.如何将接收后s分解赋值到packed record内的各个变量。

谢谢
 
直接用记录当作变量读取数据包,但是如果有拆包就不能保证数据正确,所以才出现你如上
问题。
如果确实要用记录,你先做个缓冲,将数据包保存到缓冲里面,等到包完整时,用记录类型读出来。
像上面的,最好定义包大小为<1400(MTU值),以保证不会被底层驱动拆包发送但也有可
能(有些路由器MTU值更小或其他问题导致拆包).
所以,最好是定义命令头+数据长度+数据内容这样的包发送。和FTP传输兼容最好。

我有个FTP客户端的,用SDK写的,里面的有相关操作服务器的,你看看。http://www.delphibbs.com/keylife/images/u196832/Socket_FTP060217.rar
FTP协议相关:你在网上找找看。
FTP 之传输原理篇 http://www.pc51.net/c_read10813.html
 
后退
顶部