C# Windows服务中的SFTP

C# Windows服务中的SFTP,c#,windows-services,sftp,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.Redirect

我需要通过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函数i.e服务在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

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

我假设您正在运行的外部批处理程序从未完成

重定向进程输出时,必须读取它。重定向输出的缓冲区有限。当它填充时,子进程在下一次尝试生成输出时停止,并等待父进程从缓冲区读取一些数据。由于您从不这样做,而是等待进程退出,所以会发生死锁

请参阅MSDN以了解以下信息:

同步读取操作在从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将密钥添加到 腻子的缓存和进行连接。 如果您只想继续连接一次,而不需要 将密钥添加到缓存中,输入n。 如果您不信任此主机,请按Return放弃该主机 联系 在缓存中存储密钥?是/否

您应该使用显式指定受信任主机密钥的指纹

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

旁注:命名psftp脚本.bat很容易混淆。它不是Windows批处理文件。

使用WinSCP

有关SshHostKeyFingerprint,请参阅


将p.WaitForExit更改为p.StandardOutput.ReadToEnd无效。相同的结果:好的,可能是由于一些提示,请参阅我的编辑。除了使用WinSCP库,还有其他方法修复此问题吗。因为我需要更改完整的代码,我没有足够的时间。此外,我只有私钥可以连接到服务器,但对于WinSCP,我们需要传递密码和SshHostKeyFingerprint。正如我在回答中提到的,您需要将主机密钥缓存复制到服务帐户注册表。对于WinSCP:它也支持私钥SessionOptions.SshPrivateKeyPath。关于SshHostKeyFingerprint:任何合适的SFTP/SSH库都要求您提供/验证主机密钥。这是一个重要的安全特性。请参阅和。我已确定问题所在。我的windows服务正在本地计算机帐户上运行。我已在HKEY_当前用户中注册了密钥。但由于我的Windows服务是在本地计算机帐户上运行的,所以应该将其缓存在HKEY_用户中。这可以手动完成。但是,在服务开始运行时,是否还有其他方法可以执行。sessionOptions具有参数Password,SshHostKeyFingerprint。如何得到它。我只有私钥来访问服务器,也就是说,我有服务器名、用户名和私钥来访问服务器。请帮助..获取服务器SshHostKeyFingerprint:只需运行winScp客户端windows应用程序,添加用户名/密码,应用程序将显示该密钥,或者您可以从“命令”菜单->服务器/协议信息->弹出窗口中打开winScp应用程序,其中包含该密钥。
// 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);
    //}
}