[英]How can I make asynchronous http POST requests in .Net 4.0 without encountering AccessViolationException?
我有一个在与各种网站进行通信的服务器上运行的程序。 其中一个网站很快将要求通过http POST请求进行通信,因此需要该程序的新版本。 有时,程序需要同时发出数百个POST请求,因此异步发出请求对于性能至关重要。 我现在尝试了两种编码方法,并且两种方法都因抛出AccessViolationException而以完全相同的方式间歇性地失败。 即使程序完全由托管代码组成,也会发生这种情况,因此AccessViolationExceptions应该是不可能的(请参阅Microsoft对AccessViolationException Class的评论)。
我在两周前发布了有关我的第一种编码方法的问题(请参阅...上的System.AccessViolationException。 )。 从那时起,我发现了System.Net.Http.HttpClient
类,并且我的第二种编码方法尝试使用该类,因此它与第一种方法完全不同。 修改后的代码的核心如下所示:
HttpClient httpclient = new HttpClient();
// set up httpclient with headers etc
System.Threading.CancellationTokenSource cts = new System.Threading.CancellationTokenSource();
using (StringContent sc = new StringContent(stringContent)) {
sc.Headers.ContentType = new MediaTypeWithQualityHeaderValue(ContentType);
using (Task<HttpResponseMessage> task_postasync = httpclient.PostAsync(EndPoint, sc, cts.Token)) {
task_postasync.Wait();
if (!task_postasync.IsCompleted) {
// cater for failure
}
using (HttpResponseMessage response = task_postasync.Result) {
using (Task<string> task_ReadAsStringAsync = response.Content.ReadAsStringAsync()) {
task_ReadAsStringAsync.Wait();
if (!task_ReadAsStringAsync.IsCompleted) {
// cater for failure
}
string str = task_ReadAsStringAsync.Result;
// str is the now the result of the http POST request :-)
}
}
}
}
修改后的代码和原始代码在大多数情况下都起作用,但是有时它们都因抛出AccessViolationException
失败。 此外,对于这两个代码版本,异常的位置都指定为System.Threading._IOCompletionCallback.PerformIOCompletionCallback()
。 这向我表明,这两个版本均由于.Net库中出现相同的低级错误而失败。 无论我将代码运行为32位还是64位,都会出现问题。
在服务器上,ThreadPool中的最小完成端口数量默认为24,最大数量默认为1000。大多数情况下,我一直将最小数量设置为最大1000,但是当我保留所有内容时,仍然会收到AccessViolationException
为默认值。
我试图通过启用非托管代码调试来查看异常在汇编器中的位置。 在以下代码中,当指令指针EIP
为7606336A
时,将引发异常:
76063354 nop
76063355 nop
76063356 nop
76063357 nop
76063358 mov edi,edi
7606335A push ebp
7606335B mov ebp,esp
7606335D test ecx,ecx
7606335F jne 760661DA
76063365 push dword ptr [ebp+8]
76063368 call edx
7606336A push eax
7606336B call dword ptr ds:[76060704h]
76063371 nop
76063372 nop
76063373 nop
76063374 nop
76063375 nop
76063376 mov edi,edi
76063378 push ebp
76063379 mov ebp,esp
7606337B sub esp,62Ch
76063381 mov eax,dword ptr ds:[761303ACh]
76063386 xor eax,ebp
76063388 mov dword ptr [ebp-4],eax
7606338B cmp dword ptr [ebp+8],1
7606338F push esi
76063390 mov esi,dword ptr [ebp+0Ch]
76063393 je 76066AF1
76063399 cmp dword ptr [ebp+8],2
7606339D jne 760633A8
7606339F cmp byte ptr ds:[76130002h],0
在行call edx
且寄存器edx
为零之后立即引发异常,因此在我看来,这似乎是在尝试调用内存地址为零的内容并失败。
为了帮助优化大量同时进行的Web请求,该程序提供了一个配置文件,如下所示:
<?xml version="1.0"?>
<configuration>
<system.net>
<connectionManagement>
<add address="*" maxconnection="5000"/>
</connectionManagement>
<settings>
<servicePointManager expect100Continue="false" useNagleAlgorithm="false"/>
</settings>
</system.net>
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true" />
</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
这些设置已经有很长时间了,过去在通过互联网上的多个请求获得高性能时非常有用。
我本以为发出异步http POST请求应该很容易,但是我似乎无法避免间歇性的AccessViolationException
。 有人可以帮忙吗?
我做了你所描述的事情。 我将http请求包装在BackgroundWorker中。 您可以激发很多这样的东西,并节省所有异步疯狂的工作。
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.