繁体   English   中英

如何在.Net 4.0中发出异步http POST请求而不遇到AccessViolationException?

[英]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为默认值。

我试图通过启用非托管代码调试来查看异常在汇编器中的位置。 在以下代码中,当指令指针EIP7606336A时,将引发异常:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM