如何在不遇到AccessViolationException的情况下在.Net 4.0中创建异步http POST请求?

时间:2014-01-27 21:59:34

标签: c# .net http asynchronous

我有一个在与各种网站通信的服务器上运行的程序。其中一个网站很快就要求通过http POST请求进行通信,因此需要新版本的程序。有时,程序需要同时发出几百个POST请求,因此异步发出请求对性能很重要。我现在尝试了两种编码方式,两种方式通过抛出AccessViolationException以完全相同的方式间歇性地失败。即使程序完全由托管代码组成,也会发生这种情况,因此AccessViolationExceptions应该是不可能的(请参阅Microsoft对AccessViolationException Class的评论)。

我在两周前发布了一个关于我的第一种编码方法的问题(参见System.AccessViolationException at ...)。从那以后我发现了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,但我仍然得到{{ 1}}当我将所有内容保留为默认值时。

我尝试通过运行非托管代码调试来查看汇编程序中抛出异常的位置。当以下代码中的指令指针AccessViolationExceptionEIP时抛出异常:

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为零,所以这看起来好像它试图调用内存地址为零并且失败的东西。

为了帮助优化大量的同时Web请求,程序有一个配置文件,如下所示:

edx

这些设置已经很长时间了,并且过去在通过互联网获得高性能以获得高性能时非常有用。

我原本以为制作异步http POST请求应该很容易,但我似乎无法避免间歇<?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> 。有人可以帮忙吗?

1 个答案:

答案 0 :(得分:1)

我做了类似你所描述的事情。我将http请求包装在BackgroundWorker中。你可以解雇很多很多这样的事情并为自己省去所有异步疯狂的工作。

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx