Mar*_*lot 3 windows delphi sftp windows-services winscp
我正在尝试构建一个使用 SFTP 下载一些日志文件并将它们导入数据库的服务。
因为 Delphi 没有自带 SFTP 组件,所以我创建了一个 BAT 文件来使用 WinSCP 下载日志
DownloadLogs.bat:
WinSCP.com < DownloadLogs.commands
DownloadLogs.commands:
open sftp://root:password@myserver.com
option confirm off
get -delete /var/lib/3cxpbx/Instance1/Data/Logs/CDRLogs files
exit
Run Code Online (Sandbox Code Playgroud)
这是我的服务:
procedure TsrvCentralita.ServiceExecute(Sender: TService);
const SecondsBetweenExecutions = 10;
var Counter: integer;
dmLogs: TdmLogs;
begin
Counter := 0;
while not Terminated do begin
Inc(Counter);
if Counter > SecondsBetweenExecutions then begin
Counter := 0;
dmLogs := TdmLogs.Create(Self);
try
if dmLogs.DownloadLogs then dmLogs.ImportLogs;
finally
dmLogs.Free;
end;
end;
Sleep(1000);
ServiceThread.ProcessRequests(False);
end;
end;
Run Code Online (Sandbox Code Playgroud)
这就是我调用 BAT 文件的方式:
function ExecAppWait(AppName: string; Params: string = ''; Directory: string = ''; Hidden: boolean = False): Boolean;
var ShellExInfo: TShellExecuteInfo;
begin
FillChar(ShellExInfo, SizeOf(ShellExInfo), 0);
with ShellExInfo do begin
cbSize := SizeOf(ShellExInfo);
fMask := see_Mask_NoCloseProcess;
Wnd := Application.Handle;
lpFile := PChar(AppName);
lpDirectory := PChar(Directory);
lpParameters := PChar(Params);
if Hidden then nShow := sw_Hide
else nShow := sw_ShowNormal;
end;
Result := ShellExecuteEx(@ShellExInfo);
if Result then
while WaitForSingleObject(ShellExInfo.HProcess, 100) = WAIT_TIMEOUT do begin
Application.ProcessMessages; // give processor time to other tasks
if Application.Terminated then
Break;
end;
end;
function TdmLogs.DownloadLogs(Hidden: boolean = True): boolean;
var Path: string;
begin
Path := TPath.Combine(TPath.GetDirectoryName(Application.ExeName), 'SFTP');;
ExecAppWait(TPath.Combine(Path, 'LogsCentralita.bat'), '', Hidden);
Result := Length(TDirectory.GetFiles(TPath.Combine(Path, 'Files'), '*.log')) > 0
end;
Run Code Online (Sandbox Code Playgroud)
当我在我的应用程序上调试 DownloadLogs 函数时,它工作正常,但是当作为服务运行时它会冻结。你知道出了什么问题吗?我难道不能从服务中调用 CMD.exe 吗?。
谢谢你。
更新
按照 Martin Prikryl 的回答,我现在以这种方式执行 WinSCP:
function TdmCentralita.DownloadLogs(SaveOutput: boolean = False): boolean;
var IniFile: TIniFile;
Path, Params, User, Password, Server, Hostkey, RemotePath: string;
begin
IniFile := TIniFile.Create(TPath.ChangeExtension(GetModuleName(HInstance), '.ini'));
Server := IniFile.ReadString('Centralita', 'Servidor', '');
Hostkey := IniFile.ReadString('Centralita', 'Hostkey', '');
User := IniFile.ReadString('Centralita', 'Usuario', 'root');
Password := DecryptStr(IniFile.ReadString('Centralita', 'Password', ''), 223);
RemotePath := IniFile.ReadString('Centralita', 'PathRemoto', '');
IniFile.Free;
while (RightStr(RemotePath, 1) = '\') or (RightStr(RemotePath, 1) = '/') do RemotePath := Copy(RemotePath, 1, Length(RemotePath) - 1);
RemotePath := RemotePath + '/*.log';
Path := TPath.Combine(TPath.GetDirectoryName(GetModuleName(HInstance)), 'SFTP');
if not TDirectory.Exists(TPath.Combine(Path, 'files')) then TDirectory.CreateDirectory(TPath.Combine(Path, 'files'));
Params := '/ini=null /command "open sftp://' + User + ':' + Password + '@' + Server + ' -hostkey=""' + Hostkey + '""" "option confirm off" "get -delete ' + RemotePath + ' files\*" "exit"';
if SaveOutput then Params := Params + ' /log="' + Path + '\Log.txt" /loglevel=0';
ExecAppWait('WinSCP.com', Params, Path, True);
Result := Length(TDirectory.GetFiles(TPath.Combine(Path, 'Files'), '*.log')) > 0
end;
Run Code Online (Sandbox Code Playgroud)
您的脚本不包含 SSH 主机密钥。由于您提供命令的方式很奇怪(输入重定向而不是/script或/command开关),WinSCP 以交互模式启动。所以它提示进行主机密钥验证,然后挂起。
将-hostkeyswitch添加到您的open命令中。看:
并使用/script或/command开关使 WinSCP 在任何问题上中止,而不是挂起。
您还应该阅读批处理文件输出,以便将来更好地处理错误。
| 归档时间: |
|
| 查看次数: |
280 次 |
| 最近记录: |