下载FTP文件时“尝试对无法访问的网络进行套接字操作”

时间:2015-12-16 22:24:30

标签: powershell ftp ftpwebrequest

我是PowerShell和FTP脚本的新手,所以要善待。我搜索了很多,无法找到一种方法,只需使用脚本从FTP服务器下载文件。我从cmd.exe开始尝试ftp子命令,但没有成功。所以我切换到PowerShell(v4.0)。我已经看过各种下载FTP文件的例子,但没有一个对我有用。这是我最近的尝试:

$Username = "username"
$Password = "password"
$LocalFile = "C:\Users\myuser\MyFile.xlsx"
$RemoteFile = "ftp://ftp.example.com/MyFile.xlsx"

$req = [System.Net.FtpWebRequest]::Create($RemoteFile)
$req.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$req.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$req.UseBinary = $true
$req.UsePassive = $true
$req.KeepAlive = $false

# Everything works to this point.

try {
    # This throws exception.
    $resp = [System.Net.FtpWebResponse]$req.GetResponse()
}
catch {
    $msg = $_.Exception
    Write-Host "Exception: $msg" -ForegroundColor Red
}

# More code will go here later to write the data to the local file.

# Clean up.
if ($resp -ne $null) {
    $resp.Close()
    $resp = $null
}

我得到的错误是:

System.Management.Automation.MethodInvocationException: Exception calling "GetResponse" with "0" argument(s): "The remote server returned an error: 227 Entering Passive Mode (172,16,13,205,5,250).
." ---> System.Net.WebException: The remote server returned an error: 227 Entering Passive Mode (172,16,13,205,5,250).
. ---> System.Net.Sockets.SocketException: A socket operation was attempted to an unreachable network 172.16.13.205:1530
   at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
   at System.Net.FtpControlStream.QueueOrCreateDataConection(PipelineEntry entry, ResponseDescription response, Boolean timeout, Stream& stream, Boolean& isSocketReady)
   at System.Net.FtpControlStream.PipelineCallback(PipelineEntry entry, ResponseDescription response, Boolean timeout, Stream& stream)
   at System.Net.CommandStream.PostReadCommandProcessing(Stream& stream)
   at System.Net.CommandStream.ContinueCommandPipeline()
   at System.Net.FtpWebRequest.TimedSubmitRequestHelper(Boolean async)
   at System.Net.FtpWebRequest.SubmitRequest(Boolean async)
   --- End of inner exception stack trace ---
   at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
   at System.Net.CommandStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
   at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
   at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
   at System.Net.FtpWebRequest.GetResponse()
   at CallSite.Target(Closure , CallSite , Object )
   --- End of inner exception stack trace ---
   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

我知道该文件存在且可用,因为当我将ftp://username:password@ftp.example.com/MyFile.xlsx粘贴到浏览器中时,系统会提示我下载该文件,一切正常。

FTP服务器在我们的网络中,但我想要一个适用于我们网络外的FTP服务器的解决方案。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

问题是配置错误的服务器。

  

尝试对无法访问的网络172.16.13.205:1530进行套接字操作

服务器在对227命令的PASV响应中返回其本地网络IP地址。

您的客户端(FtpWebRequest)自然无法连接到该地址并失败。

必须正确配置服务器,以便在227响应中了解并显示其外部IP地址。

有些FTP客户端可以通过以下方式克服这种错误配置:

  • 忽略227响应中不可路由的IP地址,并使用控制连接地址进行数据传输或
  • 使用EPSV命令而不是PASV(服务器仅使用端口号响应,让客户端隐式使用控制连接地址)

FtpWebRequest也无法做到。

Windows命令行FTP客户端ftp.exe甚至不支持被动模式。它仅支持主动模式,由于无处不在的NAT和防火墙,它现在几乎无法工作。

有关此类问题的详细信息,请参阅FTP connection modes (active and passive)上的我的文章。

如果您无法修复服务器,则需要使用其他FTP客户端。

例如WinSCP FTP/SFTP client使用scripting interface,您可以使用以下批处理文件(.bat):

winscp.com /log=winscp.log /command ^
    "open ftp://username:password@ftp.example.com" ^
    "get MyFile.xlsx C:\Users\myuser\MyFile.xlsx" ^
    "exit"

WinSCP忽略227响应中不可路由的IP地址,并使用控制连接地址进行数据传输。

(我是WinSCP的作者)