1

我有一个 TimeoutException 问题,我正在使用 C# 4.0(不能很快升级到 4.5)和 WCF。请注意,我不控制服务器,也看不到所使用的代码和/或技术。问题发生在不同人制作的不同服务器上。

我向多台服务器(比如说 10 台)发送尽可能多的请求,每台服务器随时发送一个请求。它们每秒发出 2 到 30 个请求。在 30 秒到 5 分钟之间,我会得到一些 TimeoutException :

exception   {"The HTTP request to 'http://xx.xx.xx.xx/service/test_service' has exceeded the allotted timeout of 00:02:10. The time allotted to this operation may have been a portion of a longer timeout."}   System.Exception {System.TimeoutException}.

Stack Trace :
Server stack trace: 
   at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult     result)
   at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeEndService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,  IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Device.EndTest(IAsyncResult result)
   at DeviceClient.EndTest(IAsyncResult result) in ...
   at TestAsync(IAsyncResult ar) in ...

内部异常是:

[System.Net.WebException]   {"The request was aborted: The request was canceled."}  System.Net.WebException
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)

Wireshark 告诉我,我什至没有打开连接(没有 SYN)。所以这应该是客户端的问题。我在 TCPView 中有很多 TIME_WAIT 连接

使用同步调用有效,但不可能。

请注意,在以下代码示例中,每个服务器都有一个方法调用。(在我的情况下,10 个并发 TestAsync)

(在实际项目中,我们使用 CCR 代替 Semaphore,结果相同)

private void AsyncTest()
{   
    //GetServiceObject Will add custom bindings and more..
    Client client = ClientBuilder.GetServiceObject();

    while (true)
    {
         Semaphore semaphore = new Semaphore(0,1);
         client.BeginTest(BeginTestCallback, new AsyncState
         {
             Client = client,
             Semaphore = semaphore
         });

         semaphore.WaitOne();   
    }   
 }

private void BeginTestCallback(IAsyncResult asyncResult)
{
    try
    {
        AsyncState state = asyncResult.AsyncState as AsyncState;

        Client client = state.Client;
        Semaphore semaphore = state.Semaphore;

        Client.EndTest(asyncResult);    

        semaphore.Release();
    }
    catch (Exception e)
    {
        //Will catch the exception here because of Client.EndTest(asyncResult)
        Debug.Assert(false, e.Message);
    }
}

我试过了

ServicePointManager.DefaultConnectionLimit = 200;
ServicePointManager.MaxServicePointIdleTime = 2000;

正如一些帖子所建议的那样,没有成功。

即使我设置了非常高的打开、发送、接收和关闭超时,它也会出现同样的异常。WCF 似乎在发送请求时“卡住”了。服务器继续正确响应其他请求。

有什么想法吗?

另外,如果我这样做(回调中的 BeginTest 而不是 while(true)),它永远不会出现异常?!?!

private void AsyncTest()
{
    //GetServiceObject Will add custom bindings and more..
    Client client = ClientBuilder.GetServiceObject();
    try
    {
        client.BeginTest(BeginTestCallback, new AsyncState
        {
            Client  = client            
        });
    }
    catch (Exception e)
    {
        Debug.Assert(false, e.Message);
    }
}

private void BeginTestCallback(IAsyncResult asyncResult)
{
    try
    {
        AsyncState state = asyncResult.AsyncState as AsyncState;        

        state.Client.EndTest(asyncResult);

        state.Client.BeginTest(BeginTestCallback, state);
    }
    catch (Exception e)
    {
        //No Exception here
        Debug.Assert(false, e.Message);
    }
}
4

1 回答 1

1

经过更多的测试,我发现如果开始/结束机制不在同一个线程池上执行,它会随机做这个行为。

在第一种情况下,“AsyncTest”是在具有 ThreadStart 和 Thread 的新线程中生成的。在第二种情况下,仅在专用线程上调用第一个“开始”,并且由于问题是随机发生的,因此在第一次请求时发生异常的可能性很小。另一个“开始”是在 .net ThreadPool 上进行的。

通过在第一种情况下使用 Task.Factory.StartNew(() => AsyncTest()),问题就消失了。

在我的真实项目中,我仍然使用 CCR(和 CCR 线程池)来做所有事情,直到我必须调用开始/结束。我将使用 .net 线程池,现在一切正常。

任何人都可以更好地解释为什么 WCF 不喜欢在另一个线程池上被调用?

于 2012-08-31T11:22:09.473 回答