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

使用工程示例:

unit Unit1; 
 
interface 
 
uses 
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
  Dialogs, StdCtrls, FTPServer; 
 
type 
  TForm1 = class(TForm) 
    btn1: TButton; 
    btn2: TButton; 
    edt_BorrowDirectory: TEdit; 
    lbl1: TLabel; 
    mmo1: TMemo; 
    lbl2: TLabel; 
    edt_BorrowPort: TEdit; 
    lbl3: TLabel; 
    edt_UserName: TEdit; 
    lbl4: TLabel; 
    edt_UserPassword: TEdit; 
    procedure btn1Click(Sender: TObject); 
    procedure btn2Click(Sender: TObject); 
    procedure TFTPServer1FtpNotifyEvent(ADatetime: TDateTime;AUserIP, AEventMessage: string); 
  private 
    FFtpServer: TFTPServer; 
  public 
    { Public declarations } 
  end; 
 
var 
  Form1: TForm1; 
 
implementation 
 
 
 
{$R *.dfm} 
 
procedure TForm1.btn1Click(Sender: TObject); 
begin 
  if not Assigned(FFtpServer) then 
  begin 
    FFtpServer := TFTPServer.Create; 
    FFtpServer.UserName := Trim(edt_UserName.Text); 
    FFtpServer.UserPassword := Trim(edt_UserPassword.Text); 
    FFtpServer.BorrowDirectory := Trim(edt_BorrowDirectory.Text); 
    FFtpServer.BorrowPort := StrToInt(Trim(edt_BorrowPort.Text)); 
    FFtpServer.OnFtpNotifyEvent := TFTPServer1FtpNotifyEvent; 
    FFtpServer.Run; 
    mmo1.Lines.Add(DateTimeToStr(Now) + #32 +'FTP服务器已开启,本机IP地址:' + FFtpServer.GetBindingIP); 
  end; 
end; 
 
procedure TForm1.btn2Click(Sender: TObject); 
begin 
  if Assigned(FFtpServer) then 
  begin 
    FFtpServer.Stop; 
    FreeAndNil(FFtpServer); 
    mmo1.Lines.Add(DateTimeToStr(Now) + #32 +'FTP服务器已关闭'); 
  end; 
end; 
 
procedure TForm1.TFTPServer1FtpNotifyEvent(ADatetime: TDateTime;AUserIP, AEventMessage: string); 
begin 
  mmo1.Lines.Add(DateTimeToStr(ADatetime) + #32 + AUserIP + #32 + AEventMessage); 
  SendMessage(mmo1.Handle,WM_VSCROLL,SB_PAGEDOWN,0); 
end; 
end. 

结果如下图所示:

示例工程源码下载:http://download.csdn.net/source/3236325

http://blog.csdn.net/akof1314/article/details/6371984#comments

最新文章

  1. AJAX JSONP源码实现(原理解析)
  2. 特性Atrribute和枚举
  3. sybase ODBC驱动
  4. SignalR入门之持久性连接
  5. Tcpdump命令详解
  6. [ucgui] 对话框3——GUIBuilder生成界面c文件及修改
  7. Dreamweaver8 查找和替换窗口不见了解决办法
  8. 【Java 基础篇】【第四课】初识类
  9. dtree的使用和扩展
  10. sscanf的用法(转)
  11. tomcat-8.0
  12. [原]H264帧内预测
  13. Lesson 7: Responsive Typography In Action
  14. 关于jquery选择器中:first和:first-child和:first-of-type的区别及:nth-child()和:nth-of-type()的区别
  15. JAVA EE 运行环境配置(包含JAVA SE)
  16. JavaScript深入之从原型到原型链(本文转载)
  17. 网络协议 22 - RPC 协议(下)- 二进制类 RPC 协议
  18. Vue中 $ref 的用法
  19. JavaSE基础知识(4)—数组的应用
  20. 在平台中使用JNDI 数据源

热门文章

  1. 与Boss大雷探讨JavaWeb开发、电商与网络安全
  2. Codeforces 106D Treasure Island 预处理前缀+暴力(水
  3. 集装箱set相关算法
  4. C++重载加号运算符实现两个结构体的相加
  5. 智能手环体验:UP24
  6. OVS 派OFPT_PORT_STATUS 流程
  7. Scala &amp; IntelliJ IDEA环境搭建升级版:在JAVA中调用Scala的helloworld
  8. 一个简单的C++性能测试工具(ms级别)
  9. 汉顺平html5课程分享:6小时制作经典的坦克大战!
  10. Spring MVC 专题