当我使用以下代码来请求FTP服务器时。 如果请求失败,我会收到错误。我不知道为什么。
代码:
try
{
FtpWebRequest request = GetFtpWebResquest(WebRequestMethods.Ftp.ListDirectoryDetails, shareInfo.Uri);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
root = new FtpResource(this, response);
}
catch (Exception e)
{
}
例外:
Unhandled Exception:
System.Net.WebException: Request aborted
at System.Net.FtpWebRequest.CheckIfAborted () [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.set_State (RequestState value) [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.ProcessRequest () [0x00000] in <filename unknown>:0
at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.Net.WebException: Request aborted
at System.Net.FtpWebRequest.CheckIfAborted () [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.set_State (RequestState value) [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.ProcessRequest () [0x00000] in <filename unknown>:0
at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
@@@ ABORTING: INVALID HEAP ADDRESS IN dlfree addr=0x420e3580
_wapi_handle_ref: Attempting to ref unused handle 0x41c
* Assertion at /Users/builder/data/lanes/monodroid-lion-bs1/03814ac5/source/mono/mono/io-layer/wthreads.c:1365, condition `ok' not met
编辑: 为了更好地理解,我实现了一个从AsyncTask调用的简单测试方法。 AsnycTask启动一次,除了GUI线程和AsyncTask之外我不使用其他线程。 在几秒钟的间隔内,AsyncTask接收我的ListView的所有条目并设置状态(离线/在线)。 2到3分钟后,我得到了上面未处理的例外。
AsynTask:
#region implemented abstract members of AsyncTask
protected override Java.Lang.Object DoInBackground (params Java.Lang.Object[] @params)
{
try
{
_isRunning = true;
while (_isRunning)
{
if (Statics.IsInternetAvailable(_context))
{
AvailableShareAdapter adapter = _context.GetAvailableSharesAdapter();
if (adapter != null)
{
List<ShareInformation> list = adapter.GetAllItems();
foreach(ShareInformation si in list)
{
if (!_isRunning)
break;
si.State = ShareInformation.ShareState.Testing;
_handler.Post(new Java.Lang.Runnable(() => { _context.GetAvailableSharesAdapter().NotifyDataSetChanged(); } ));
if (_coreFacade.SimpleTest(si.Uri, si.UserName, si.Password))
si.State = ShareInformation.ShareState.Online;
else
si.State = ShareInformation.ShareState.Offline;
_handler.Post(new Java.Lang.Runnable(() => { _context.GetAvailableSharesAdapter().NotifyDataSetChanged(); } ));
}
}
Thread.Sleep(60000);
}
}
} catch(Exception e)
{
_coreFacade.Log("DoInBackground", e.ToString());
}
return null;
}
#endregion
SimpleTest:
public bool SimpleTest(string uri, string username, string password)
{
Console.WriteLine("SimpleTest called");
try {
WebRequest request = HttpWebRequest.Create(uri);
request.Credentials = new NetworkCredential(username, password);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.Timeout = 30 * 1000;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
return true;
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
return false;
}
}
编辑2: 顺便说一下......当连接失败时,我只得到这个未处理的异常。如果可用的FTP源工作正常。
答案 0 :(得分:4)
简短回答:这是一个Mono bug(实际上是FtpWebRequest中的一个)。 切换到备用FTP客户端类/ libary(例如J.P. Trosclair的 System.Net.FtpClient),如果可能的话。
答案很长:
抛出“请求中止”异常的线程是一个运行时创建的线程,这就是为什么你不能捕获异常(以及运行时终止的原因)。
我最近遇到了同样的问题,花了很长时间调试它。
如果你看一下Mono的FtpWebRequest(截至目前的最新资料):
您将看到ProcessRequest(来自您的堆栈跟踪)是一个ThreadStart委托,并且感兴趣的线程确实由运行时创建(第391和442行)。
事实证明,FtpWebReuqest.GetResponse()虽然是每个规范同步,但实际上是异步的[sic!] - 第422行。这创造了动态环境(我们很快就会看到)容易出错
以下是其中一种失败方案(TCP connect()超时):
[calling thread] Create(); // FtpWebRequest object, State == RequestState.Before
[calling thread] GetResponse();
[calling thread] BeginGetResponse();
[calling thread] State = RequestState.Scheduled;
[calling thread] new Thread(ProcessRequest()).Start() // runtime-created thread
[calling thread] EndGetResponse();
[calling thread] WaitUntilComplete();
[runtime thread] ProcessRequest();
[runtime thread] ProcessMethod();
[runtime thread] State = RequestState.Connecting;
[runtime thread] OpenControlConnection();
[runtime thread] Socket.Connect();
<time passes>
[calling thread] Abort(); // WaitUntilComplete() times out
[calling thread] State = RequestState.Aborted; // [!!]
[calling thread] throw WebException("Transfer timed out");
// calling thread seems to think everything's fine, but...
<some time later>
[runtime thread] throw SocketException // Socket.Connect() times out
[runtime thread] sock = null; // from exception handler
[runtime thread] throw WebException("unable to connect to remote server");
// because sock was set to null
[runtime thread] State = RequestState.Error;
// exception is caught in ProcessRequest, an attempt is made to
// change the State to RequestState.Error, but it's already been
// set to RequestState.Aborted by the calling thread [!!]
[runtime thread] throw WebException("Request aborted");
// and this exception isn't caught anywhere... *KABOOM*
Aaaand就是这样的。不幸的是,修复属于Mono。
你肯定可以尝试通过设置超出底层套接字的connect()超时的超时来解决它,但事实是,很少有其他代码路径可以让Mono抛出无法处理的异常...... : - (