2014-10-06 55 views
1

我需要通过C#代码执行SFTP进程。我正在使用Windows服务。以下是我正在使用的代码。Windows服务中的SFTP

WebCash.writeToFile(WebCash.outerbatchpath, command); 
WebCash.writeToFile(WebCash.outerbatchpath, "exit"); 

ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/c "+WebCash.outerbatchpath); 
psi.RedirectStandardOutput = true; 
psi.RedirectStandardInput = true; 
psi.RedirectStandardError = true; 
psi.UseShellExecute = false; 
psi.CreateNoWindow = true; 
psi.WindowStyle = ProcessWindowStyle.Hidden; 
Process p = new Process(); 
p.StartInfo = psi; 
p.Start(); 
p.WaitForExit(); 

psi = null; 
WebCash.writeToFile(WebCash.GetErrorLog(), DateTime.Now.ToString() + "- Running SFTP end - " + p.ExitCode); 
return p.ExitCode; 

虽然试图调试上面的代码调试器不能够通过p.WaitforExit()函数(即)服务没有p.WaitforExit()之后执行。

我在我的外部运行下面的命令(SFTP)。

psftp -b D:\Source_Data\SFTP\innerbatch.bat -l username -i D:\privatekey.ppk @servername 

内蒙古批次包含以下命令

put D:\Source_Data\SFTP\FileToTransfer.xml 

我需要退出代码也得到了错误。请帮助。

回答

0

我假设你正在运行的程序(“外部批次”)永远不会结束。

当您重定向流程输出时,您必须正在读取它。重定向输出有一个有限的缓冲区。填充时,子进程在下一次尝试产生输出时停止,并等待父进程从缓冲区读取一些数据。如果你从不这样做,并且你等待进程退出,就会发生死锁。

请参阅MSDN的ProcessStartInfo.RedirectStandardOutput property

同步读取操作介绍呼叫者从StandardOutput流和子进程写入该流读取之间的相关性。这些依赖关系可能导致死锁情况。当调用者从子进程的重定向流中读取时,它依赖于子进程。调用者等待读取操作,直到孩子写入流或关闭流。当子进程写入足够的数据以填充其重定向流时,它依赖于父进程。子进程等待下一个写操作,直到父进程从完整流读取或关闭流。当调用者和子进程等待彼此完成操作并且两者都不能继续时,将导致死锁情况。您可以通过评估调用者和子进程之间的依赖关系来避免死锁。

在这种情况下,总是建议使用p.StandardOutput.ReadToEnd()而不是p.WaitForExit()。两个命令都等待进程退出,但第一个命令确保不会发生死锁。

另一方面,由于您只传输一个文件,所以我不确定psftp输出实际上足够大以填充缓冲区。如果上述建议不起作用,我建议您通过直接运行psftp.exe来简化代码,删除不必要的cmd.exe层和外部批处理文件。

编辑:如果您从未在服务帐户下运行psftp,它可能会提示主机密钥确认。

服务器的主机密钥没有缓存在注册表中。您
不能保证服务器是您认为它是
的计算机。
服务器的DSS密钥指纹是:
SSH-DSS 1024 0B:77:8B:68:F4:45:B1:3C:87:广告:5C:是:3B:C5:72:78
如果信任此主机,输入“y”将密钥添加到
PuTTY的缓存并进行连接。
如果您只想继续连接一次,而没有
将密钥添加到缓存中,请输入“n”。
如果您不信任此主机,请按回车键以放弃
连接。
将密钥存储在缓存中? (y/n)

您应该使用-hostkey switch明确指定可信主机密钥的指纹。

或者使用一些本地SFTP .NET库。

附注:命名psftp脚本.bat令人困惑。它不是(Windows)批处理文件。

+0

我已经更新我的答案。 – 2014-10-07 07:38:45

+0

将p.WaitForExit()更改为p.StandardOutput.ReadToEnd()不起作用。同样的结果:( – user3859666 2014-10-07 14:07:51

+0

好的,比它很可能是由于某些提示,请参阅我的编辑 – 2014-10-07 15:33:44

0

使用WinSCP。

SshHostKeyFingerprint看到Server and Protocol Information Dialog

// Setup session options 
SessionOptions sessionOptions = new SessionOptions 
{ 
    Protocol = Protocol.Sftp, 
    HostName = "000.00.00.000", 
    UserName = "xxxxxx", 
    Password = "xxxxxx", 
    PortNumber= 22, 
    SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxxxxxx" 
}; 

using (Session session = new Session()) 
{ 
    // Connect 
    session.Open(sessionOptions); 

    // Upload files 
    //TransferOptions transferOptions = new TransferOptions(); 
    //transferOptions.TransferMode = TransferMode.Binary; 

    //TransferOperationResult transferResult; 
    var results = session.ListDirectory("/path"); 
    foreach (RemoteFileInfo item in results.Files) 
    { 
     Console.WriteLine(item.Name); 
    } 

    // Throw on any error 
    //transferResult.Check(); 

    // Print results 
    //foreach (TransferEventArgs transfer in transferResult.Transfers) 
    //{ 
    // Console.WriteLine("Upload of {0} succeeded", transfer.FileName); 
    //} 
} 
+0

sessionOptions具有参数Password,SshHostKeyFingerprint。如何得到这个。我只有私钥才能访问服务器(即)我有Servername,用户名和私钥来访问服务器。请帮助.. – user3859666 2014-10-08 04:55:01

+0

获取您的服务器SshHostKeyFingerprint:只需运行winScp客户端“windows应用程序”,添加用户名/密码,应用程序就会显示该密钥,或者您可以从命令菜单 - >服务器/协议信息打开WinScp应用程序 - >弹出窗口包含该键。 – 2014-10-15 06:36:55