在Delphi 7开发下有强大的Indy控件,版本为9,要实现一个FTP服务器,参考自带的例子,发现还要写很多函数,而且不支持中文显示文件列表等等。
于是,自己改进封装了下,形成一个TFTPServer类。
源码如下:
1 {*******************************************************}
2 { }
3 { 系统名称 FTP服务器类 }
4 { 版权所有 (C) http://blog.csdn.net/akof1314 }
5 { 单元名称 FTPServer.pas }
6 { 单元功能 在Delphi 7下TIdFTPServer实现FTP服务器 }
7 { }
8 {*******************************************************}
9 unit FTPServer;
10
11 interface
12
13 uses
14 Classes, Windows, Sysutils, IdFTPList, IdFTPServer, Idtcpserver, IdSocketHandle, Idglobal, IdHashCRC, IdStack;
15 {-------------------------------------------------------------------------------
16 功能: 自定义消息,方便与窗体进行消息传递
17 -------------------------------------------------------------------------------}
18 type
19 TFtpNotifyEvent = procedure (ADatetime: TDateTime;AUserIP, AEventMessage: string) of object;
20 {-------------------------------------------------------------------------------
21 功能: FTP服务器类
22 -------------------------------------------------------------------------------}
23 type
24 TFTPServer = class
25 private
26 FUserName,FUserPassword,FBorrowDirectory: string;
27 FBorrowPort: Integer;
28 IdFTPServer: TIdFTPServer;
29 FOnFtpNotifyEvent: TFtpNotifyEvent;
30 procedure IdFTPServer1UserLogin( ASender: TIdFTPServerThread; const AUsername, APassword: string; var AAuthenticated: Boolean ) ;
31 procedure IdFTPServer1ListDirectory( ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems ) ;
32 procedure IdFTPServer1RenameFile( ASender: TIdFTPServerThread; const ARenameFromFile, ARenameToFile: string ) ;
33 procedure IdFTPServer1RetrieveFile( ASender: TIdFTPServerThread; const AFilename: string; var VStream: TStream ) ;
34 procedure IdFTPServer1StoreFile( ASender: TIdFTPServerThread; const AFilename: string; AAppend: Boolean; var VStream: TStream ) ;
35 procedure IdFTPServer1RemoveDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
36 procedure IdFTPServer1MakeDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
37 procedure IdFTPServer1GetFileSize( ASender: TIdFTPServerThread; const AFilename: string; var VFileSize: Int64 ) ;
38 procedure IdFTPServer1DeleteFile( ASender: TIdFTPServerThread; const APathname: string ) ;
39 procedure IdFTPServer1ChangeDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
40 procedure IdFTPServer1CommandXCRC( ASender: TIdCommand ) ;
41 procedure IdFTPServer1DisConnect( AThread: TIdPeerThread ) ;
42 protected
43 function TransLatePath( const APathname, homeDir: string ) : string;
44 public
45 constructor Create; reintroduce;
46 destructor Destroy; override;
47 procedure Run;
48 procedure Stop;
49 function GetBindingIP():string;
50 property UserName: string read FUserName write FUserName;
51 property UserPassword: string read FUserPassword write FUserPassword;
52 property BorrowDirectory: string read FBorrowDirectory write FBorrowDirectory;
53 property BorrowPort: Integer read FBorrowPort write FBorrowPort;
54 property OnFtpNotifyEvent: TFtpNotifyEvent read FOnFtpNotifyEvent write FOnFtpNotifyEvent;
55 end;
56
57 implementation
58
59 {-------------------------------------------------------------------------------
60 过程名: TFTPServer.Create
61 功能: 创建函数
62 参数: 无
63 返回值: 无
64 -------------------------------------------------------------------------------}
65 constructor TFTPServer.Create;
66 begin
67 IdFTPServer := tIdFTPServer.create( nil ) ;
68 IdFTPServer.DefaultPort := 21; //默认端口号
69 IdFTPServer.AllowAnonymousLogin := False; //是否允许匿名登录
70 IdFTPServer.EmulateSystem := ftpsUNIX;
71 IdFTPServer.HelpReply.text := '帮助还未实现!';
72 IdFTPServer.OnChangeDirectory := IdFTPServer1ChangeDirectory;
73 IdFTPServer.OnGetFileSize := IdFTPServer1GetFileSize;
74 IdFTPServer.OnListDirectory := IdFTPServer1ListDirectory;
75 IdFTPServer.OnUserLogin := IdFTPServer1UserLogin;
76 IdFTPServer.OnRenameFile := IdFTPServer1RenameFile;
77 IdFTPServer.OnDeleteFile := IdFTPServer1DeleteFile;
78 IdFTPServer.OnRetrieveFile := IdFTPServer1RetrieveFile;
79 IdFTPServer.OnStoreFile := IdFTPServer1StoreFile;
80 IdFTPServer.OnMakeDirectory := IdFTPServer1MakeDirectory;
81 IdFTPServer.OnRemoveDirectory := IdFTPServer1RemoveDirectory;
82 IdFTPServer.Greeting.Text.Text := '欢迎进入FTP服务器';
83 IdFTPServer.Greeting.NumericCode := 220;
84 IdFTPServer.OnDisconnect := IdFTPServer1DisConnect;
85 with IdFTPServer.CommandHandlers.add do
86 begin
87 Command := 'XCRC'; //可以迅速验证所下载的文档是否和源文档一样
88 OnCommand := IdFTPServer1CommandXCRC;
89 end;
90 end;
91 {-------------------------------------------------------------------------------
92 过程名: CalculateCRC
93 功能: 计算CRC
94 参数: const path: string
95 返回值: string
96 -------------------------------------------------------------------------------}
97 function CalculateCRC( const path: string ) : string;
98 var
99 f: tfilestream;
100 value: dword;
101 IdHashCRC32: TIdHashCRC32;
102 begin
103 IdHashCRC32 := nil;
104 f := nil;
105 try
106 IdHashCRC32 := TIdHashCRC32.create;
107 f := TFileStream.create( path, fmOpenRead or fmShareDenyWrite ) ;
108 value := IdHashCRC32.HashValue( f ) ;
109 result := inttohex( value, 8 ) ;
110 finally
111 f.free;
112 IdHashCRC32.free;
113 end;
114 end;
115
116 {-------------------------------------------------------------------------------
117 过程名: TFTPServer.IdFTPServer1CommandXCRC
118 功能: XCRC命令
119 参数: ASender: TIdCommand
120 返回值: 无
121 -------------------------------------------------------------------------------}
122 procedure TFTPServer.IdFTPServer1CommandXCRC( ASender: TIdCommand ) ;
123 // note, this is made up, and not defined in any rfc.
124 var
125 s: string;
126 begin
127 with TIdFTPServerThread( ASender.Thread ) do
128 begin
129 if Authenticated then
130 begin
131 try
132 s := ProcessPath( CurrentDir, ASender.UnparsedParams ) ;
133 s := TransLatePath( s, TIdFTPServerThread( ASender.Thread ) .HomeDir ) ;
134 ASender.Reply.SetReply( 213, CalculateCRC( s ) ) ;
135 except
136 ASender.Reply.SetReply( 500, 'file error' ) ;
137 end;
138 end;
139 end;
140 end;
141
142 {-------------------------------------------------------------------------------
143 过程名: TFTPServer.Destroy
144 功能: 析构函数
145 参数: 无
146 返回值: 无
147 -------------------------------------------------------------------------------}
148 destructor TFTPServer.Destroy;
149 begin
150 IdFTPServer.free;
151 inherited destroy;
152 end;
153
154 function StartsWith( const str, substr: string ) : boolean;
155 begin
156 result := copy( str, 1, length( substr ) ) = substr;
157 end;
158
159 {-------------------------------------------------------------------------------
160 过程名: TFTPServer.Run
161 功能: 开启服务
162 参数: 无
163 返回值: 无
164 -------------------------------------------------------------------------------}
165 procedure TFTPServer.Run;
166 begin
167 IdFTPServer.DefaultPort := BorrowPort;
168 IdFTPServer.Active := True;
169 end;
170
171 {-------------------------------------------------------------------------------
172 过程名: TFTPServer.Stop
173 功能: 关闭服务
174 参数: 无
175 返回值: 无
176 -------------------------------------------------------------------------------}
177 procedure TFTPServer.Stop;
178 begin
179 IdFTPServer.Active := False;
180 end;
181
182 {-------------------------------------------------------------------------------
183 过程名: TFTPServer.GetBindingIP
184 功能: 获取绑定的IP地址
185 参数:
186 返回值: string
187 -------------------------------------------------------------------------------}
188 function TFTPServer.GetBindingIP():string ;
189 begin
190 Result := GStack.LocalAddress;
191 end;
192 {-------------------------------------------------------------------------------
193 过程名: BackSlashToSlash
194 功能: 反斜杠到斜杠
195 参数: const str: string
196 返回值: string
197 -------------------------------------------------------------------------------}
198 function BackSlashToSlash( const str: string ) : string;
199 var
200 a: dword;
201 begin
202 result := str;
203 for a := 1 to length( result ) do
204 if result[a] = '/' then
205 result[a] := '/';
206 end;
207
208 {-------------------------------------------------------------------------------
209 过程名: SlashToBackSlash
210 功能: 斜杠到反斜杠
211 参数: const str: string
212 返回值: string
213 -------------------------------------------------------------------------------}
214 function SlashToBackSlash( const str: string ) : string;
215 var
216 a: dword;
217 begin
218 result := str;
219 for a := 1 to length( result ) do
220 if result[a] = '/' then
221 result[a] := '/';
222 end;
223
224 {-------------------------------------------------------------------------------
225 过程名: TFTPServer.TransLatePath
226 功能: 路径名称翻译
227 参数: const APathname, homeDir: string
228 返回值: string
229 -------------------------------------------------------------------------------}
230 function TFTPServer.TransLatePath( const APathname, homeDir: string ) : string;
231 var
232 tmppath: string;
233 begin
234 result := SlashToBackSlash(Utf8ToAnsi(homeDir) ) ;
235 tmppath := SlashToBackSlash( Utf8ToAnsi(APathname) ) ;
236 if homedir = '/' then
237 begin
238 result := tmppath;
239 exit;
240 end;
241
242 if length( APathname ) = 0 then
243 exit;
244 if result[length( result ) ] = '/' then
245 result := copy( result, 1, length( result ) - 1 ) ;
246 if tmppath[1] <> '/' then
247 result := result + '/';
248 result := result + tmppath;
249 end;
250
251 {-------------------------------------------------------------------------------
252 过程名: GetNewDirectory
253 功能: 得到新目录
254 参数: old, action: string
255 返回值: string
256 -------------------------------------------------------------------------------}
257 function GetNewDirectory( old, action: string ) : string;
258 var
259 a: integer;
260 begin
261 if action = '../' then
262 begin
263 if old = '/' then
264 begin
265 result := old;
266 exit;
267 end;
268 a := length( old ) - 1;
269 while ( old[a] <> '/' ) and ( old[a] <> '/' ) do
270 dec( a ) ;
271 result := copy( old, 1, a ) ;
272 exit;
273 end;
274 if ( action[1] = '/' ) or ( action[1] = '/' ) then
275 result := action
276 else
277 result := old + action;
278 end;
279
280 {-------------------------------------------------------------------------------
281 过程名: TFTPServer.IdFTPServer1UserLogin
282 功能: 允许服务器执行一个客户端连接的用户帐户身份验证
283 参数: ASender: TIdFTPServerThread; const AUsername, APassword: string; var AAuthenticated: Boolean
284 返回值: 无
285 -------------------------------------------------------------------------------}
286 procedure TFTPServer.IdFTPServer1UserLogin( ASender: TIdFTPServerThread;
287 const AUsername, APassword: string; var AAuthenticated: Boolean ) ;
288 begin
289 AAuthenticated := ( AUsername = UserName ) and ( APassword = UserPassword ) ;
290 if not AAuthenticated then
291 exit;
292 ASender.HomeDir := AnsiToUtf8(BorrowDirectory);
293 asender.currentdir := '/';
294 if Assigned(FOnFtpNotifyEvent) then
295 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'用户登录服务器');
296 end;
297
298 {-------------------------------------------------------------------------------
299 过程名: TFTPServer.IdFTPServer1ListDirectory
300 功能: 允许服务器生成格式化的目录列表
301 参数: ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems
302 返回值: 无
303 -------------------------------------------------------------------------------}
304 procedure TFTPServer.IdFTPServer1ListDirectory( ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems ) ;
305
306 procedure AddlistItem( aDirectoryListing: TIdFTPListItems; Filename: string; ItemType: TIdDirItemType; size: int64; date: tdatetime ) ;
307 var
308 listitem: TIdFTPListItem;
309 begin
310 listitem := aDirectoryListing.Add;
311 listitem.ItemType := ItemType; //表示一个文件系统的属性集
312 listitem.FileName := AnsiToUtf8(Filename); //名称分配给目录中的列表项,这里防止了中文乱码
313 listitem.OwnerName := 'anonymous';//代表了用户拥有的文件或目录项的名称
314 listitem.GroupName := 'all'; //指定组名拥有的文件名称或目录条目
315 listitem.OwnerPermissions := 'rwx'; //拥有者权限,R读W写X执行
316 listitem.GroupPermissions := 'rwx'; //组拥有者权限
317 listitem.UserPermissions := 'rwx'; //用户权限,基于用户和组权限
318 listitem.Size := size;
319 listitem.ModifiedDate := date;
320 end;
321
322 var
323 f: tsearchrec;
324 a: integer;
325 begin
326 ADirectoryListing.DirectoryName := apath;
327 a := FindFirst( TransLatePath( apath, ASender.HomeDir ) + '*.*', faAnyFile, f ) ;
328 while ( a = 0 ) do
329 begin
330 if ( f.Attr and faDirectory > 0 ) then
331 AddlistItem( ADirectoryListing, f.Name, ditDirectory, f.size, FileDateToDateTime( f.Time ) )
332 else
333 AddlistItem( ADirectoryListing, f.Name, ditFile, f.size, FileDateToDateTime( f.Time ) ) ;
334 a := FindNext( f ) ;
335 end;
336
337 FindClose( f ) ;
338 end;
339
340 {-------------------------------------------------------------------------------
341 过程名: TFTPServer.IdFTPServer1RenameFile
342 功能: 允许服务器重命名服务器文件系统中的文件
343 参数: ASender: TIdFTPServerThread; const ARenameFromFile, ARenameToFile: string
344 返回值: 无
345 -------------------------------------------------------------------------------}
346 procedure TFTPServer.IdFTPServer1RenameFile( ASender: TIdFTPServerThread;
347 const ARenameFromFile, ARenameToFile: string ) ;
348 begin
349 try
350 if not MoveFile( pchar( TransLatePath( ARenameFromFile, ASender.HomeDir ) ) , pchar( TransLatePath( ARenameToFile, ASender.HomeDir ) ) ) then
351 RaiseLastOSError;
352 except
353 on e:Exception do
354 begin
355 if Assigned(FOnFtpNotifyEvent) then
356 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'重命名文件[' + Utf8ToAnsi(ARenameFromFile) + ']失败,原因是' + e.Message);
357 Exit;
358 end;
359 end;
360 if Assigned(FOnFtpNotifyEvent) then
361 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'重命名文件[' + Utf8ToAnsi(ARenameFromFile) + ']为[' + Utf8ToAnsi(ARenameToFile) + ']');
362 end;
363
364 {-------------------------------------------------------------------------------
365 过程名: TFTPServer.IdFTPServer1RetrieveFile
366 功能: 允许从服务器下载文件系统中的文件
367 参数: ASender: TIdFTPServerThread; const AFilename: string; var VStream: TStream
368 返回值: 无
369 -------------------------------------------------------------------------------}
370 procedure TFTPServer.IdFTPServer1RetrieveFile( ASender: TIdFTPServerThread;
371 const AFilename: string; var VStream: TStream ) ;
372 begin
373 VStream := TFileStream.Create( translatepath( AFilename, ASender.HomeDir ) , fmopenread or fmShareDenyWrite ) ;
374 if Assigned(FOnFtpNotifyEvent) then
375 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'下载文件[' + Utf8ToAnsi(AFilename) + ']');
376 end;
377
378 {-------------------------------------------------------------------------------
379 过程名: TFTPServer.IdFTPServer1StoreFile
380 功能: 允许在服务器上传文件系统中的文件
381 参数: ASender: TIdFTPServerThread; const AFilename: string; AAppend: Boolean; var VStream: TStream
382 返回值: 无
383 -------------------------------------------------------------------------------}
384 procedure TFTPServer.IdFTPServer1StoreFile( ASender: TIdFTPServerThread;
385 const AFilename: string; AAppend: Boolean; var VStream: TStream ) ;
386 begin
387 if FileExists( translatepath( AFilename, ASender.HomeDir ) ) and AAppend then
388 begin
389 VStream := TFileStream.create( translatepath( AFilename, ASender.HomeDir ) , fmOpenWrite or fmShareExclusive ) ;
390 VStream.Seek( 0, soFromEnd ) ;
391 end
392 else
393 VStream := TFileStream.create( translatepath( AFilename, ASender.HomeDir ) , fmCreate or fmShareExclusive ) ;
394 if Assigned(FOnFtpNotifyEvent) then
395 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'上传文件[' + Utf8ToAnsi(AFilename) + ']');
396 end;
397
398 {-------------------------------------------------------------------------------
399 过程名: TFTPServer.IdFTPServer1RemoveDirectory
400 功能: 允许服务器在服务器删除文件系统的目录
401 参数: ASender: TIdFTPServerThread; var VDirectory: string
402 返回值: 无
403 -------------------------------------------------------------------------------}
404 procedure TFTPServer.IdFTPServer1RemoveDirectory( ASender: TIdFTPServerThread;
405 var VDirectory: string ) ;
406 begin
407 try
408 RmDir( TransLatePath( VDirectory, ASender.HomeDir ) ) ;
409 except
410 on e:Exception do
411 begin
412 if Assigned(FOnFtpNotifyEvent) then
413 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除目录[' + Utf8ToAnsi(VDirectory) + ']失败,原因是' + e.Message);
414 Exit;
415 end;
416 end;
417 if Assigned(FOnFtpNotifyEvent) then
418 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除目录[' + Utf8ToAnsi(VDirectory) + ']');
419 end;
420
421 {-------------------------------------------------------------------------------
422 过程名: TFTPServer.IdFTPServer1MakeDirectory
423 功能: 允许服务器从服务器中创建一个新的子目录
424 参数: ASender: TIdFTPServerThread; var VDirectory: string
425 返回值: 无
426 -------------------------------------------------------------------------------}
427 procedure TFTPServer.IdFTPServer1MakeDirectory( ASender: TIdFTPServerThread;
428 var VDirectory: string ) ;
429 begin
430 try
431 MkDir( TransLatePath( VDirectory, ASender.HomeDir ) ) ;
432 except
433 on e:Exception do
434 begin
435 if Assigned(FOnFtpNotifyEvent) then
436 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'创建目录[' + Utf8ToAnsi(VDirectory) + ']失败,原因是' + e.Message);
437 Exit;
438 end;
439 end;
440 if Assigned(FOnFtpNotifyEvent) then
441 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'创建目录[' + Utf8ToAnsi(VDirectory) + ']');
442 end;
443
444 {-------------------------------------------------------------------------------
445 过程名: TFTPServer.IdFTPServer1GetFileSize
446 功能: 允许服务器检索在服务器文件系统的文件的大小
447 参数: ASender: TIdFTPServerThread; const AFilename: string; var VFileSize: Int64
448 返回值: 无
449 -------------------------------------------------------------------------------}
450 procedure TFTPServer.IdFTPServer1GetFileSize( ASender: TIdFTPServerThread;
451 const AFilename: string; var VFileSize: Int64 ) ;
452 begin
453 VFileSize := FileSizeByName( TransLatePath( AFilename, ASender.HomeDir ) ) ;
454 if Assigned(FOnFtpNotifyEvent) then
455 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'获取文件大小');
456 end;
457
458 {-------------------------------------------------------------------------------
459 过程名: TFTPServer.IdFTPServer1DeleteFile
460 功能: 允许从服务器中删除的文件系统中的文件
461 参数: ASender: TIdFTPServerThread; const APathname: string
462 返回值: 无
463 -------------------------------------------------------------------------------}
464 procedure TFTPServer.IdFTPServer1DeleteFile( ASender: TIdFTPServerThread;
465 const APathname: string ) ;
466 begin
467 try
468 DeleteFile( pchar( TransLatePath( ASender.CurrentDir + '/' + APathname, ASender.HomeDir ) ) ) ;
469 except
470 on e:Exception do
471 begin
472 if Assigned(FOnFtpNotifyEvent) then
473 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除文件[' + Utf8ToAnsi(APathname) + ']失败,原因是' + e.Message);
474 Exit;
475 end;
476 end;
477 if Assigned(FOnFtpNotifyEvent) then
478 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除文件[' + Utf8ToAnsi(APathname) + ']');
479 end;
480
481 {-------------------------------------------------------------------------------
482 过程名: TFTPServer.IdFTPServer1ChangeDirectory
483 功能: 允许服务器选择一个文件系统路径
484 参数: ASender: TIdFTPServerThread; var VDirectory: string
485 返回值: 无
486 -------------------------------------------------------------------------------}
487 procedure TFTPServer.IdFTPServer1ChangeDirectory( ASender: TIdFTPServerThread;
488 var VDirectory: string ) ;
489 begin
490 VDirectory := GetNewDirectory( ASender.CurrentDir, VDirectory ) ;
491 if Assigned(FOnFtpNotifyEvent) then
492 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'进入目录[' + Utf8ToAnsi(VDirectory) + ']');
493 end;
494
495 {-------------------------------------------------------------------------------
496 过程名: TFTPServer.IdFTPServer1DisConnect
497 功能: 失去网络连接
498 参数: AThread: TIdPeerThread
499 返回值: 无
500 -------------------------------------------------------------------------------}
501 procedure TFTPServer.IdFTPServer1DisConnect( AThread: TIdPeerThread ) ;
502 begin
503 // nothing much here
504 end;
505 end.
使用工程示例:
1 unit Unit1;
2
3 interface
4
5 uses
6 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7 Dialogs, StdCtrls, FTPServer;
8
9 type
10 TForm1 = class(TForm)
11 btn1: TButton;
12 btn2: TButton;
13 edt_BorrowDirectory: TEdit;
14 lbl1: TLabel;
15 mmo1: TMemo;
16 lbl2: TLabel;
17 edt_BorrowPort: TEdit;
18 lbl3: TLabel;
19 edt_UserName: TEdit;
20 lbl4: TLabel;
21 edt_UserPassword: TEdit;
22 procedure btn1Click(Sender: TObject);
23 procedure btn2Click(Sender: TObject);
24 procedure TFTPServer1FtpNotifyEvent(ADatetime: TDateTime;AUserIP, AEventMessage: string);
25 private
26 FFtpServer: TFTPServer;
27 public
28 { Public declarations }
29 end;
30
31 var
32 Form1: TForm1;
33
34 implementation
35
36
37
38 {$R *.dfm}
39
40 procedure TForm1.btn1Click(Sender: TObject);
41 begin
42 if not Assigned(FFtpServer) then
43 begin
44 FFtpServer := TFTPServer.Create;
45 FFtpServer.UserName := Trim(edt_UserName.Text);
46 FFtpServer.UserPassword := Trim(edt_UserPassword.Text);
47 FFtpServer.BorrowDirectory := Trim(edt_BorrowDirectory.Text);
48 FFtpServer.BorrowPort := StrToInt(Trim(edt_BorrowPort.Text));
49 FFtpServer.OnFtpNotifyEvent := TFTPServer1FtpNotifyEvent;
50 FFtpServer.Run;
51 mmo1.Lines.Add(DateTimeToStr(Now) + #32 +'FTP服务器已开启,本机IP地址:' + FFtpServer.GetBindingIP);
52 end;
53 end;
54
55 procedure TForm1.btn2Click(Sender: TObject);
56 begin
57 if Assigned(FFtpServer) then
58 begin
59 FFtpServer.Stop;
60 FreeAndNil(FFtpServer);
61 mmo1.Lines.Add(DateTimeToStr(Now) + #32 +'FTP服务器已关闭');
62 end;
63 end;
64
65 procedure TForm1.TFTPServer1FtpNotifyEvent(ADatetime: TDateTime;AUserIP, AEventMessage: string);
66 begin
67 mmo1.Lines.Add(DateTimeToStr(ADatetime) + #32 + AUserIP + #32 + AEventMessage);
68 SendMessage(mmo1.Handle,WM_VSCROLL,SB_PAGEDOWN,0);
69 end;
70 end.
结果如下图所示:

示例工程源码下载:
http://download.csdn.net/source/3236325
原博客地址:
http://blog.csdn.net/akof1314/article/details/6371984#comments
https://www.cnblogs.com/findumars/p/6360865.html
1 {*******************************************************}
2 { }
3 { 系统名称 FTP服务器类 }
4 { 版权所有 (C) http://blog.csdn.net/akof1314 }
5 { 单元名称 FTPServer.pas }
6 { 单元功能 在Delphi 7下TIdFTPServer实现FTP服务器 }
7 { }
8 {*******************************************************}
9 unit FTPServer;
10
11 interface
12
13 uses
14 Classes, Windows, Sysutils, IdFTPList, IdFTPServer, Idtcpserver, IdSocketHandle, Idglobal, IdHashCRC, IdStack;
15 {-------------------------------------------------------------------------------
16 功能: 自定义消息,方便与窗体进行消息传递
17 -------------------------------------------------------------------------------}
18 type
19 TFtpNotifyEvent = procedure (ADatetime: TDateTime;AUserIP, AEventMessage: string) of object;
20 {-------------------------------------------------------------------------------
21 功能: FTP服务器类
22 -------------------------------------------------------------------------------}
23 type
24 TFTPServer = class
25 private
26 FUserName,FUserPassword,FBorrowDirectory: string;
27 FBorrowPort: Integer;
28 IdFTPServer: TIdFTPServer;
29 FOnFtpNotifyEvent: TFtpNotifyEvent;
30 procedure IdFTPServer1UserLogin( ASender: TIdFTPServerThread; const AUsername, APassword: string; var AAuthenticated: Boolean ) ;
31 procedure IdFTPServer1ListDirectory( ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems ) ;
32 procedure IdFTPServer1RenameFile( ASender: TIdFTPServerThread; const ARenameFromFile, ARenameToFile: string ) ;
33 procedure IdFTPServer1RetrieveFile( ASender: TIdFTPServerThread; const AFilename: string; var VStream: TStream ) ;
34 procedure IdFTPServer1StoreFile( ASender: TIdFTPServerThread; const AFilename: string; AAppend: Boolean; var VStream: TStream ) ;
35 procedure IdFTPServer1RemoveDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
36 procedure IdFTPServer1MakeDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
37 procedure IdFTPServer1GetFileSize( ASender: TIdFTPServerThread; const AFilename: string; var VFileSize: Int64 ) ;
38 procedure IdFTPServer1DeleteFile( ASender: TIdFTPServerThread; const APathname: string ) ;
39 procedure IdFTPServer1ChangeDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
40 procedure IdFTPServer1CommandXCRC( ASender: TIdCommand ) ;
41 procedure IdFTPServer1DisConnect( AThread: TIdPeerThread ) ;
42 protected
43 function TransLatePath( const APathname, homeDir: string ) : string;
44 public
45 constructor Create; reintroduce;
46 destructor Destroy; override;
47 procedure Run;
48 procedure Stop;
49 function GetBindingIP():string;
50 property UserName: string read FUserName write FUserName;
51 property UserPassword: string read FUserPassword write FUserPassword;
52 property BorrowDirectory: string read FBorrowDirectory write FBorrowDirectory;
53 property BorrowPort: Integer read FBorrowPort write FBorrowPort;
54 property OnFtpNotifyEvent: TFtpNotifyEvent read FOnFtpNotifyEvent write FOnFtpNotifyEvent;
55 end;
56
57 implementation
58
59 {-------------------------------------------------------------------------------
60 过程名: TFTPServer.Create
61 功能: 创建函数
62 参数: 无
63 返回值: 无
64 -------------------------------------------------------------------------------}
65 constructor TFTPServer.Create;
66 begin
67 IdFTPServer := tIdFTPServer.create( nil ) ;
68 IdFTPServer.DefaultPort := 21; //默认端口号
69 IdFTPServer.AllowAnonymousLogin := False; //是否允许匿名登录
70 IdFTPServer.EmulateSystem := ftpsUNIX;
71 IdFTPServer.HelpReply.text := '帮助还未实现!';
72 IdFTPServer.OnChangeDirectory := IdFTPServer1ChangeDirectory;
73 IdFTPServer.OnGetFileSize := IdFTPServer1GetFileSize;
74 IdFTPServer.OnListDirectory := IdFTPServer1ListDirectory;
75 IdFTPServer.OnUserLogin := IdFTPServer1UserLogin;
76 IdFTPServer.OnRenameFile := IdFTPServer1RenameFile;
77 IdFTPServer.OnDeleteFile := IdFTPServer1DeleteFile;
78 IdFTPServer.OnRetrieveFile := IdFTPServer1RetrieveFile;
79 IdFTPServer.OnStoreFile := IdFTPServer1StoreFile;
80 IdFTPServer.OnMakeDirectory := IdFTPServer1MakeDirectory;
81 IdFTPServer.OnRemoveDirectory := IdFTPServer1RemoveDirectory;
82 IdFTPServer.Greeting.Text.Text := '欢迎进入FTP服务器';
83 IdFTPServer.Greeting.NumericCode := 220;
84 IdFTPServer.OnDisconnect := IdFTPServer1DisConnect;
85 with IdFTPServer.CommandHandlers.add do
86 begin
87 Command := 'XCRC'; //可以迅速验证所下载的文档是否和源文档一样
88 OnCommand := IdFTPServer1CommandXCRC;
89 end;
90 end;
91 {-------------------------------------------------------------------------------
92 过程名: CalculateCRC
93 功能: 计算CRC
94 参数: const path: string
95 返回值: string
96 -------------------------------------------------------------------------------}
97 function CalculateCRC( const path: string ) : string;
98 var
99 f: tfilestream;
100 value: dword;
101 IdHashCRC32: TIdHashCRC32;
102 begin
103 IdHashCRC32 := nil;
104 f := nil;
105 try
106 IdHashCRC32 := TIdHashCRC32.create;
107 f := TFileStream.create( path, fmOpenRead or fmShareDenyWrite ) ;
108 value := IdHashCRC32.HashValue( f ) ;
109 result := inttohex( value, 8 ) ;
110 finally
111 f.free;
112 IdHashCRC32.free;
113 end;
114 end;
115
116 {-------------------------------------------------------------------------------
117 过程名: TFTPServer.IdFTPServer1CommandXCRC
118 功能: XCRC命令
119 参数: ASender: TIdCommand
120 返回值: 无
121 -------------------------------------------------------------------------------}
122 procedure TFTPServer.IdFTPServer1CommandXCRC( ASender: TIdCommand ) ;
123 // note, this is made up, and not defined in any rfc.
124 var
125 s: string;
126 begin
127 with TIdFTPServerThread( ASender.Thread ) do
128 begin
129 if Authenticated then
130 begin
131 try
132 s := ProcessPath( CurrentDir, ASender.UnparsedParams ) ;
133 s := TransLatePath( s, TIdFTPServerThread( ASender.Thread ) .HomeDir ) ;
134 ASender.Reply.SetReply( 213, CalculateCRC( s ) ) ;
135 except
136 ASender.Reply.SetReply( 500, 'file error' ) ;
137 end;
138 end;
139 end;
140 end;
141
142 {-------------------------------------------------------------------------------
143 过程名: TFTPServer.Destroy
144 功能: 析构函数
145 参数: 无
146 返回值: 无
147 -------------------------------------------------------------------------------}
148 destructor TFTPServer.Destroy;
149 begin
150 IdFTPServer.free;
151 inherited destroy;
152 end;
153
154 function StartsWith( const str, substr: string ) : boolean;
155 begin
156 result := copy( str, 1, length( substr ) ) = substr;
157 end;
158
159 {-------------------------------------------------------------------------------
160 过程名: TFTPServer.Run
161 功能: 开启服务
162 参数: 无
163 返回值: 无
164 -------------------------------------------------------------------------------}
165 procedure TFTPServer.Run;
166 begin
167 IdFTPServer.DefaultPort := BorrowPort;
168 IdFTPServer.Active := True;
169 end;
170
171 {-------------------------------------------------------------------------------
172 过程名: TFTPServer.Stop
173 功能: 关闭服务
174 参数: 无
175 返回值: 无
176 -------------------------------------------------------------------------------}
177 procedure TFTPServer.Stop;
178 begin
179 IdFTPServer.Active := False;
180 end;
181
182 {-------------------------------------------------------------------------------
183 过程名: TFTPServer.GetBindingIP
184 功能: 获取绑定的IP地址
185 参数:
186 返回值: string
187 -------------------------------------------------------------------------------}
188 function TFTPServer.GetBindingIP():string ;
189 begin
190 Result := GStack.LocalAddress;
191 end;
192 {-------------------------------------------------------------------------------
193 过程名: BackSlashToSlash
194 功能: 反斜杠到斜杠
195 参数: const str: string
196 返回值: string
197 -------------------------------------------------------------------------------}
198 function BackSlashToSlash( const str: string ) : string;
199 var
200 a: dword;
201 begin
202 result := str;
203 for a := 1 to length( result ) do
204 if result[a] = '/' then
205 result[a] := '/';
206 end;
207
208 {-------------------------------------------------------------------------------
209 过程名: SlashToBackSlash
210 功能: 斜杠到反斜杠
211 参数: const str: string
212 返回值: string
213 -------------------------------------------------------------------------------}
214 function SlashToBackSlash( const str: string ) : string;
215 var
216 a: dword;
217 begin
218 result := str;
219 for a := 1 to length( result ) do
220 if result[a] = '/' then
221 result[a] := '/';
222 end;
223
224 {-------------------------------------------------------------------------------
225 过程名: TFTPServer.TransLatePath
226 功能: 路径名称翻译
227 参数: const APathname, homeDir: string
228 返回值: string
229 -------------------------------------------------------------------------------}
230 function TFTPServer.TransLatePath( const APathname, homeDir: string ) : string;
231 var
232 tmppath: string;
233 begin
234 result := SlashToBackSlash(Utf8ToAnsi(homeDir) ) ;
235 tmppath := SlashToBackSlash( Utf8ToAnsi(APathname) ) ;
236 if homedir = '/' then
237 begin
238 result := tmppath;
239 exit;
240 end;
241
242 if length( APathname ) = 0 then
243 exit;
244 if result[length( result ) ] = '/' then
245 result := copy( result, 1, length( result ) - 1 ) ;
246 if tmppath[1] <> '/' then
247 result := result + '/';
248 result := result + tmppath;
249 end;
250
251 {-------------------------------------------------------------------------------
252 过程名: GetNewDirectory
253 功能: 得到新目录
254 参数: old, action: string
255 返回值: string
256 -------------------------------------------------------------------------------}
257 function GetNewDirectory( old, action: string ) : string;
258 var
259 a: integer;
260 begin
261 if action = '../' then
262 begin
263 if old = '/' then
264 begin
265 result := old;
266 exit;
267 end;
268 a := length( old ) - 1;
269 while ( old[a] <> '/' ) and ( old[a] <> '/' ) do
270 dec( a ) ;
271 result := copy( old, 1, a ) ;
272 exit;
273 end;
274 if ( action[1] = '/' ) or ( action[1] = '/' ) then
275 result := action
276 else
277 result := old + action;
278 end;
279
280 {-------------------------------------------------------------------------------
281 过程名: TFTPServer.IdFTPServer1UserLogin
282 功能: 允许服务器执行一个客户端连接的用户帐户身份验证
283 参数: ASender: TIdFTPServerThread; const AUsername, APassword: string; var AAuthenticated: Boolean
284 返回值: 无
285 -------------------------------------------------------------------------------}
286 procedure TFTPServer.IdFTPServer1UserLogin( ASender: TIdFTPServerThread;
287 const AUsername, APassword: string; var AAuthenticated: Boolean ) ;
288 begin
289 AAuthenticated := ( AUsername = UserName ) and ( APassword = UserPassword ) ;
290 if not AAuthenticated then
291 exit;
292 ASender.HomeDir := AnsiToUtf8(BorrowDirectory);
293 asender.currentdir := '/';
294 if Assigned(FOnFtpNotifyEvent) then
295 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'用户登录服务器');
296 end;
297
298 {-------------------------------------------------------------------------------
299 过程名: TFTPServer.IdFTPServer1ListDirectory
300 功能: 允许服务器生成格式化的目录列表
301 参数: ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems
302 返回值: 无
303 -------------------------------------------------------------------------------}
304 procedure TFTPServer.IdFTPServer1ListDirectory( ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems ) ;
305
306 procedure AddlistItem( aDirectoryListing: TIdFTPListItems; Filename: string; ItemType: TIdDirItemType; size: int64; date: tdatetime ) ;
307 var
308 listitem: TIdFTPListItem;
309 begin
310 listitem := aDirectoryListing.Add;
311 listitem.ItemType := ItemType; //表示一个文件系统的属性集
312 listitem.FileName := AnsiToUtf8(Filename); //名称分配给目录中的列表项,这里防止了中文乱码
313 listitem.OwnerName := 'anonymous';//代表了用户拥有的文件或目录项的名称
314 listitem.GroupName := 'all'; //指定组名拥有的文件名称或目录条目
315 listitem.OwnerPermissions := 'rwx'; //拥有者权限,R读W写X执行
316 listitem.GroupPermissions := 'rwx'; //组拥有者权限
317 listitem.UserPermissions := 'rwx'; //用户权限,基于用户和组权限
318 listitem.Size := size;
319 listitem.ModifiedDate := date;
320 end;
321
322 var
323 f: tsearchrec;
324 a: integer;
325 begin
326 ADirectoryListing.DirectoryName := apath;
327 a := FindFirst( TransLatePath( apath, ASender.HomeDir ) + '*.*', faAnyFile, f ) ;
328 while ( a = 0 ) do
329 begin
330 if ( f.Attr and faDirectory > 0 ) then
331 AddlistItem( ADirectoryListing, f.Name, ditDirectory, f.size, FileDateToDateTime( f.Time ) )
332 else
333 AddlistItem( ADirectoryListing, f.Name, ditFile, f.size, FileDateToDateTime( f.Time ) ) ;
334 a := FindNext( f ) ;
335 end;
336
337 FindClose( f ) ;
338 end;
339
340 {-------------------------------------------------------------------------------
341 过程名: TFTPServer.IdFTPServer1RenameFile
342 功能: 允许服务器重命名服务器文件系统中的文件
343 参数: ASender: TIdFTPServerThread; const ARenameFromFile, ARenameToFile: string
344 返回值: 无
345 -------------------------------------------------------------------------------}
346 procedure TFTPServer.IdFTPServer1RenameFile( ASender: TIdFTPServerThread;
347 const ARenameFromFile, ARenameToFile: string ) ;
348 begin
349 try
350 if not MoveFile( pchar( TransLatePath( ARenameFromFile, ASender.HomeDir ) ) , pchar( TransLatePath( ARenameToFile, ASender.HomeDir ) ) ) then
351 RaiseLastOSError;
352 except
353 on e:Exception do
354 begin
355 if Assigned(FOnFtpNotifyEvent) then
356 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'重命名文件[' + Utf8ToAnsi(ARenameFromFile) + ']失败,原因是' + e.Message);
357 Exit;
358 end;
359 end;
360 if Assigned(FOnFtpNotifyEvent) then
361 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'重命名文件[' + Utf8ToAnsi(ARenameFromFile) + ']为[' + Utf8ToAnsi(ARenameToFile) + ']');
362 end;
363
364 {-------------------------------------------------------------------------------
365 过程名: TFTPServer.IdFTPServer1RetrieveFile
366 功能: 允许从服务器下载文件系统中的文件
367 参数: ASender: TIdFTPServerThread; const AFilename: string; var VStream: TStream
368 返回值: 无
369 -------------------------------------------------------------------------------}
370 procedure TFTPServer.IdFTPServer1RetrieveFile( ASender: TIdFTPServerThread;
371 const AFilename: string; var VStream: TStream ) ;
372 begin
373 VStream := TFileStream.Create( translatepath( AFilename, ASender.HomeDir ) , fmopenread or fmShareDenyWrite ) ;
374 if Assigned(FOnFtpNotifyEvent) then
375 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'下载文件[' + Utf8ToAnsi(AFilename) + ']');
376 end;
377
378 {-------------------------------------------------------------------------------
379 过程名: TFTPServer.IdFTPServer1StoreFile
380 功能: 允许在服务器上传文件系统中的文件
381 参数: ASender: TIdFTPServerThread; const AFilename: string; AAppend: Boolean; var VStream: TStream
382 返回值: 无
383 -------------------------------------------------------------------------------}
384 procedure TFTPServer.IdFTPServer1StoreFile( ASender: TIdFTPServerThread;
385 const AFilename: string; AAppend: Boolean; var VStream: TStream ) ;
386 begin
387 if FileExists( translatepath( AFilename, ASender.HomeDir ) ) and AAppend then
388 begin
389 VStream := TFileStream.create( translatepath( AFilename, ASender.HomeDir ) , fmOpenWrite or fmShareExclusive ) ;
390 VStream.Seek( 0, soFromEnd ) ;
391 end
392 else
393 VStream := TFileStream.create( translatepath( AFilename, ASender.HomeDir ) , fmCreate or fmShareExclusive ) ;
394 if Assigned(FOnFtpNotifyEvent) then
395 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'上传文件[' + Utf8ToAnsi(AFilename) + ']');
396 end;
397
398 {-------------------------------------------------------------------------------
399 过程名: TFTPServer.IdFTPServer1RemoveDirectory
400 功能: 允许服务器在服务器删除文件系统的目录
401 参数: ASender: TIdFTPServerThread; var VDirectory: string
402 返回值: 无
403 -------------------------------------------------------------------------------}
404 procedure TFTPServer.IdFTPServer1RemoveDirectory( ASender: TIdFTPServerThread;
405 var VDirectory: string ) ;
406 begin
407 try
408 RmDir( TransLatePath( VDirectory, ASender.HomeDir ) ) ;
409 except
410 on e:Exception do
411 begin
412 if Assigned(FOnFtpNotifyEvent) then
413 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除目录[' + Utf8ToAnsi(VDirectory) + ']失败,原因是' + e.Message);
414 Exit;
415 end;
416 end;
417 if Assigned(FOnFtpNotifyEvent) then
418 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除目录[' + Utf8ToAnsi(VDirectory) + ']');
419 end;
420
421 {-------------------------------------------------------------------------------
422 过程名: TFTPServer.IdFTPServer1MakeDirectory
423 功能: 允许服务器从服务器中创建一个新的子目录
424 参数: ASender: TIdFTPServerThread; var VDirectory: string
425 返回值: 无
426 -------------------------------------------------------------------------------}
427 procedure TFTPServer.IdFTPServer1MakeDirectory( ASender: TIdFTPServerThread;
428 var VDirectory: string ) ;
429 begin
430 try
431 MkDir( TransLatePath( VDirectory, ASender.HomeDir ) ) ;
432 except
433 on e:Exception do
434 begin
435 if Assigned(FOnFtpNotifyEvent) then
436 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'创建目录[' + Utf8ToAnsi(VDirectory) + ']失败,原因是' + e.Message);
437 Exit;
438 end;
439 end;
440 if Assigned(FOnFtpNotifyEvent) then
441 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'创建目录[' + Utf8ToAnsi(VDirectory) + ']');
442 end;
443
444 {-------------------------------------------------------------------------------
445 过程名: TFTPServer.IdFTPServer1GetFileSize
446 功能: 允许服务器检索在服务器文件系统的文件的大小
447 参数: ASender: TIdFTPServerThread; const AFilename: string; var VFileSize: Int64
448 返回值: 无
449 -------------------------------------------------------------------------------}
450 procedure TFTPServer.IdFTPServer1GetFileSize( ASender: TIdFTPServerThread;
451 const AFilename: string; var VFileSize: Int64 ) ;
452 begin
453 VFileSize := FileSizeByName( TransLatePath( AFilename, ASender.HomeDir ) ) ;
454 if Assigned(FOnFtpNotifyEvent) then
455 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'获取文件大小');
456 end;
457
458 {-------------------------------------------------------------------------------
459 过程名: TFTPServer.IdFTPServer1DeleteFile
460 功能: 允许从服务器中删除的文件系统中的文件
461 参数: ASender: TIdFTPServerThread; const APathname: string
462 返回值: 无
463 -------------------------------------------------------------------------------}
464 procedure TFTPServer.IdFTPServer1DeleteFile( ASender: TIdFTPServerThread;
465 const APathname: string ) ;
466 begin
467 try
468 DeleteFile( pchar( TransLatePath( ASender.CurrentDir + '/' + APathname, ASender.HomeDir ) ) ) ;
469 except
470 on e:Exception do
471 begin
472 if Assigned(FOnFtpNotifyEvent) then
473 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除文件[' + Utf8ToAnsi(APathname) + ']失败,原因是' + e.Message);
474 Exit;
475 end;
476 end;
477 if Assigned(FOnFtpNotifyEvent) then
478 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除文件[' + Utf8ToAnsi(APathname) + ']');
479 end;
480
481 {-------------------------------------------------------------------------------
482 过程名: TFTPServer.IdFTPServer1ChangeDirectory
483 功能: 允许服务器选择一个文件系统路径
484 参数: ASender: TIdFTPServerThread; var VDirectory: string
485 返回值: 无
486 -------------------------------------------------------------------------------}
487 procedure TFTPServer.IdFTPServer1ChangeDirectory( ASender: TIdFTPServerThread;
488 var VDirectory: string ) ;
489 begin
490 VDirectory := GetNewDirectory( ASender.CurrentDir, VDirectory ) ;
491 if Assigned(FOnFtpNotifyEvent) then
492 OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'进入目录[' + Utf8ToAnsi(VDirectory) + ']');
493 end;
494
495 {-------------------------------------------------------------------------------
496 过程名: TFTPServer.IdFTPServer1DisConnect
497 功能: 失去网络连接
498 参数: AThread: TIdPeerThread
499 返回值: 无
500 -------------------------------------------------------------------------------}
501 procedure TFTPServer.IdFTPServer1DisConnect( AThread: TIdPeerThread ) ;
502 begin
503 // nothing much here
504 end;
505 end.
1 unit Unit1;
2
3 interface
4
5 uses
6 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7 Dialogs, StdCtrls, FTPServer;
8
9 type
10 TForm1 = class(TForm)
11 btn1: TButton;
12 btn2: TButton;
13 edt_BorrowDirectory: TEdit;
14 lbl1: TLabel;
15 mmo1: TMemo;
16 lbl2: TLabel;
17 edt_BorrowPort: TEdit;
18 lbl3: TLabel;
19 edt_UserName: TEdit;
20 lbl4: TLabel;
21 edt_UserPassword: TEdit;
22 procedure btn1Click(Sender: TObject);
23 procedure btn2Click(Sender: TObject);
24 procedure TFTPServer1FtpNotifyEvent(ADatetime: TDateTime;AUserIP, AEventMessage: string);
25 private
26 FFtpServer: TFTPServer;
27 public
28 { Public declarations }
29 end;
30
31 var
32 Form1: TForm1;
33
34 implementation
35
36
37
38 {$R *.dfm}
39
40 procedure TForm1.btn1Click(Sender: TObject);
41 begin
42 if not Assigned(FFtpServer) then
43 begin
44 FFtpServer := TFTPServer.Create;
45 FFtpServer.UserName := Trim(edt_UserName.Text);
46 FFtpServer.UserPassword := Trim(edt_UserPassword.Text);
47 FFtpServer.BorrowDirectory := Trim(edt_BorrowDirectory.Text);
48 FFtpServer.BorrowPort := StrToInt(Trim(edt_BorrowPort.Text));
49 FFtpServer.OnFtpNotifyEvent := TFTPServer1FtpNotifyEvent;
50 FFtpServer.Run;
51 mmo1.Lines.Add(DateTimeToStr(Now) + #32 +'FTP服务器已开启,本机IP地址:' + FFtpServer.GetBindingIP);
52 end;
53 end;
54
55 procedure TForm1.btn2Click(Sender: TObject);
56 begin
57 if Assigned(FFtpServer) then
58 begin
59 FFtpServer.Stop;
60 FreeAndNil(FFtpServer);
61 mmo1.Lines.Add(DateTimeToStr(Now) + #32 +'FTP服务器已关闭');
62 end;
63 end;
64
65 procedure TForm1.TFTPServer1FtpNotifyEvent(ADatetime: TDateTime;AUserIP, AEventMessage: string);
66 begin
67 mmo1.Lines.Add(DateTimeToStr(ADatetime) + #32 + AUserIP + #32 + AEventMessage);
68 SendMessage(mmo1.Handle,WM_VSCROLL,SB_PAGEDOWN,0);
69 end;
70 end.
