Windows服务中的SFTP

时间:2014-10-06 13:53:35

标签: c# windows-services sftp

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

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

我还需要退出代码来获取错误。请帮助。

2 个答案:

答案 0 :(得分: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:ad:5c:be:3b:c5:72:78
  如果您信任此主机,请输入" y"将密钥添加到
  PuTTY的缓存并进行连接。
  如果你想只进行一次连接,没有
  将密钥添加到缓存中,输入" n"。
  如果您不信任此主机,请按Return键放弃   连接。
  将密钥存储在缓存中? (Y / N)

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

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

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

答案 1 :(得分: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);
    //}
}