Mono for Android / MonoTouch System.Net.WebException:请求已中止(Mono for Android / MonoTouch System.Net.W

编程入门 行业动态 更新时间:2024-10-05 07:21:25
Mono for Android / MonoTouch System.Net.WebException:请求已中止(Mono for Android / MonoTouch System.Net.WebException: Request aborted)

当我使用以下代码来请求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源一切正常。

When I use the following code for a request to a FTP server. If the request failed I get an error. I don't know why.

Code:

try { FtpWebRequest request = GetFtpWebResquest(WebRequestMethods.Ftp.ListDirectoryDetails, shareInfo.Uri); FtpWebResponse response = (FtpWebResponse)request.GetResponse(); root = new FtpResource(this, response); } catch (Exception e) { }

Exception:

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

EDIT : For a better understanding I implemenent a simple test method called from an AsyncTask. The AsnycTask is starting once and I don't use an other thread except the GUI thread and this AsyncTask. In intervals of a few seconds the AsyncTask receives all entries of my ListView and set the state (offline/online). After 2 - 3 minutes I get the unhandled exception above.

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; } }

EDIT 2 : By the way...I only get this unhandled exception when the connection failed. If the FTP source available all works fine.

最满意答案

简短的回答:这是一个Mono bug(实际上是FtpWebRequest中的一个)。 如果可能,切换到备用FTP客户端类/ libary(例如JP Trosclair的System.Net.FtpClient)。

答案很长:

抛出“请求中止”异常的线程是运行时创建的线程,这就是您无法捕获异常(以及运行时终止的原因)的原因。

我最近遇到了同样的问题,花了很长时间调试它。

如果你看一下Mono的FtpWebRequest(截至目前的最新资料):

https://github.com/mono/mono/blob/5aeeb9cf7b558b8a92a7eb7d6a524cc4e7b60191/mcs/class/System/System.Net/FtpWebRequest.cs

你会看到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可以抛出无法处理的异常...... :-(

Short answer: it's a Mono bug (one of several in FtpWebRequest, actually). Switch to alternative FTP client class/libary (such as J.P. Trosclair's System.Net.FtpClient), if possible.

Long answer:

The thread that throws "Request aborted" exception is a runtime-created thread that's why you can't catch the exception (and why the runtime terminates).

I've run into same issue recently and spent quite some time debugging it.

If you look at Mono's FtpWebRequest (latest source as of now):

https://github.com/mono/mono/blob/5aeeb9cf7b558b8a92a7eb7d6a524cc4e7b60191/mcs/class/System/System.Net/FtpWebRequest.cs

you'll see that ProcessRequest (from your stack trace) is a ThreadStart delegate and that the thread of interest is indeed created by the runtime (lines 391 and 442).

It turns out that FtpWebReuqest.GetResponse(), while synchronous per specification, is actually asynchronous under the hood [sic!] -- line 422. This creates dynamic environment which is (as we'll shortly see) error-prone.

Here's what happens in one of failing scenarios (TCP connect() timeout):

[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 that's how it happens. Unfortunately, the fix belongs in Mono.

You sure could try to work around it by setting a timeout that exceeds connect() timeout of the underlying socket but the truth is that there are few other code paths where Mono can throw exceptions that don't get handled... :-(

更多推荐

本文发布于:2023-07-09 10:22:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1085609.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:MonoTouch   System   Mono   Android   Request

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!