套接字连接已中止 - CommunicationException

时间:2010-08-09 15:58:22

标签: c# .net wcf exception-handling

最初:

  • 我认为这是一个循环参考问题........原来它不是。
  • 问题产生于完全没有配置服务配置。
  • 由于默认值非常低,因此发送大量数据会导致服务崩溃。

情境:

  • 我的WCF服务似乎有循环引用,但使用“[DataContract(IsReference = true)]”,没有任何帮助解决它。
  • 我收到错误“套接字连接已中止。这可能是由于处理消息时出错或远程主机超出接收超时或基础网络资源问题引起的。本地套接字超时为'00:01 :00' “
  • 我错过了什么吗?

代码:

[DataContract(IsReference=true)]
public class Message
{
    [DataMember]
    public string TopicName { get; set; }

    [DataMember]
    public string EventData { get; set; }

    [DataMember]
    public SerializableDictionary<string, FuturesLineAsset> FuturesLineDictionary { get; set ; }
}

思想:

  • 我想知道是不是因为我有一个类FuturesAsset,它有一个BindableDictionary类型的属性(这是一个CUSTOM OBJECT),并且该属性包含一个FuturesLinesAssets列表。
  • 见下文:

父:

public class FuturesAsset
{
    public string AssetName { get; set; }
    public BindableDictionary<string, FuturesLineAsset> AssetLines { get; private set; }

    public FuturesAsset()
    {
        AssetLines = new BindableDictionary<string, FuturesLineAsset>();
    }

    public FuturesAsset(string assetName)
    {
        AssetLines = new BindableDictionary<string, FuturesLineAsset>();
        AssetName = assetName;
    }
}

子:

public class FuturesLineAsset
{

    public string ReferenceAsset { get; set; }
    public string MID { get; set; }
    public double LivePrice { get; set; }
    public DateTime UpdateTime { get; set; }
    public DateTime LastContributedTime { get; set; }
    public double Spread { get; set; }
    public double Correlation { get; set; }
    public DateTime Maturity { get; set; }
    public double ReferenceCurve { get; set; }

    public FuturesLineAsset(string mID, string referenceAsset, double livePrice)
    {
        MID = mID;
        ReferenceAsset = referenceAsset;
        ReutersLivePrice = livePrice;
    }
}

7 个答案:

答案 0 :(得分:19)

此错误可能是由许多事情引起的。虽然在这种情况下这是一个时间问题,但它通常与时间无关,尤其是如果立即收到错误。可能的原因是:

  • 合同中用作参数或返回类型的对象没有无参数构造函数,并且未使用DataContract属性进行修饰。检查用作参数或返回类型的类,以及这些类的公共属性使用的所有类型。如果使用其中一个类的参数实现构造函数,编译器将不再为您添加默认的无参数构造函数,因此您需要自己添加它。
  • 服务配置中定义的默认限制太低(MaxItemsInObjectGraph,MaxReceivedMessageSize,MaxBufferPoolSize,MaxBufferSize,MaxArrayLength)。
  • DataContract对象的某些公共属性是只读的。确保所有公共属性都有getter和setter。

答案 1 :(得分:12)

该例外与循环参考无关,当您尝试通过线路抽取大量数据时,它只是完全超时。

WCF附带的默认值非常低(我相信在WCF 4中已经更改了这些值)。阅读这两篇博客文章,他们应该让您知道如何解决您的服务:

Creating high performance WCF services

How to throttle a Wcf service, help prevent DoS attacks, and maintain Wcf scalability

更新:此外,WCF配置中有许多不同的超时,并且取决于它是您正在谈论的客户端还是服务器,您需要更新不同的超时子句...阅读这个thread关于每个人的意思,你应该能够弄清楚你需要提出哪一个。 ,如果你真的不在乎呼叫是否需要很长时间才能完成,你可以将每个超时设置为int.max。

答案 2 :(得分:3)

从Windows服务主机安装程序的OnStart事件中调用了长时间的初始化过程会出现此问题。通过设置TCP绑定的安全模式和超时来修复。

            // Create a channel factory.
            NetTcpBinding b = new NetTcpBinding();
            b.Security.Mode = SecurityMode.Transport;
            b.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
            b.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;

            b.MaxReceivedMessageSize = 1000000;
            b.OpenTimeout = TimeSpan.FromMinutes(2);
            b.SendTimeout = TimeSpan.FromMinutes(2);
            b.ReceiveTimeout = TimeSpan.FromMinutes(10);

答案 3 :(得分:2)

此问题也可能是由于在您完成使用后未清理WCF客户端。在我们的系统中,我们使用一次性模式并将所有函数调用包装到系统中,以便进行适当的清理和记录。我们使用以下类的版本:

    public class WcfWrapper : IDisposable
    {
        private readonly OperationContextScope _operationContextScope;
        private readonly IClientChannel _clientChannel;

        public WcfWrapper(IClientChannel clientChannel)
        {
            _clientChannel = clientChannel;
            _operationContextScope = new OperationContextScope(_clientChannel);
        }



        public void Dispose()
        {
            _operationContextScope.Dispose();
        }


        public T Function<T>(Func<T> func)
        {
            try
            {
                var result = func();
                _clientChannel.Close();
                return result;
            }
            catch (Exception ex)
            {
                KTrace.Error(ex);
                _clientChannel.Abort();
                throw;
            }

        }

        public void Procedure(Action action)
        {
            try
            {
                action();
                _clientChannel.Close();
            }
            catch (Exception ex)
            {
                KTrace.Error(ex);
                _clientChannel.Abort();
                throw;
            }
        }
    }

}

我们在服务中进行的每个WCF调用都是通过定义的接口类完成的,如下所示:

    public sealed class WcfLoginManager : ILoginManager
    {
        private static LoginManagerClient GetWcfClient()
        {
            return 
                new LoginManagerClient(
                    WcfBindingHelper.GetBinding(),
                    WcfBindingHelper.GetEndpointAddress(ServiceUrls.LoginManagerUri));

        }

        public LoginResponse Login(LoginRequest request)
        {
            using(var loginManagerClient = GetWcfClient())
            using (var slice = new WcfWrapper(loginManagerClient.InnerChannel))
            {
                DSTicket ticket;
                DSAccount account;
                return slice.Function(() => new LoginResponse(loginManagerClient.Login(request.accountName, request.credentials, out ticket, out account), ticket, account));
            }
        }
    }

使用此模式,系统中的所有WCF调用都包含Function或Procedure方法,允许它们首先确保在所有错误上进行日志记录,然后确保在没有错误发生时关闭通道但是在中止时发生异常。最后,正如它在using语句中一样,调用了最终的通道处理。通过这种方式,可以防止由于通道未正确清理而出现的错误,这些错误看起来像这个错误。

答案 4 :(得分:1)

当我返回一个包含IEnumerable集合的对象时,我发生了这个异常,并且在检索其中一个集合成员时发生了异常。此时,在代码中捕获它已经太晚了,并且可能在这种情况下WCF被设计为断开套接字,因为向客户端报告异常也为时已晚,因为它已经开始流式传输结果。

答案 5 :(得分:0)

WCF错误:

  

套接字连接已中止。这可能是由错误引起的   处理您的消息或超过接收超时   远程主机或底层网络资源问题。本地套接字   超时是......

报告的超时非常接近1分钟(例如00:00:59.9680000)或1分钟(即00:01:00)可能是由于邮件太大而导致exceeding the settings for the binding

这可以通过增加配置文件中的值来修复,例如:

<binding name="MyWcfBinding" 
         maxReceivedMessageSize="10000000" 
         maxBufferSize="10000000" 
         maxBufferPoolSize="10000000" />

(仅限示例值,您可能需要调整它们)。

答案 6 :(得分:0)

在我的情况下,我试图用net tcp实例化Wcf。因此,如果在web.config的绑定部分中,您将“ netTcpBinding”配置为这样

<bindings>
    <netTcpBinding>
        <binding name="bindingName" closeTimeout="01:10:00" openTimeout="01:10:00" receiveTimeout="01:10:00" sendTimeout="01:10:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxConnections="10" maxReceivedMessageSize="2147483647" portSharingEnabled="true">
            <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="16384"/>
            <reliableSession ordered="true" inactivityTimeout="01:10:00" enabled="false"/>
            <security mode="None"/>
        </binding>
    </netTcpBinding>
</bindings>

然后,您需要使用服务接口的名称空间配置服务部分,以使用合同属性定义端点,并放置baseAddres,类似这样

<services>
  <service behaviorConfiguration="sgiBehavior" name="Enterprise.Tecnic.SGI.OP.Wcf.OP">
    <endpoint address="" behaviorConfiguration="endPointBehavior" binding="webHttpBinding" bindingConfiguration="BindingWebHttp" name="endPointHttp" contract="Enterprise.Tecnic.SGI.OP.Interface.IOP"/>
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
    <endpoint address="" binding="netTcpBinding" bindingConfiguration="bindingName"
      name="EndpointNetTcp" contract="Enterprise.Tecnic.SGI.OP.Interface.IOP" />

    <host>
      <baseAddresses>
        <!--  <add baseAddress="http://localhost:61217/OP.svc"/> -->
        <add baseAddress="http://www.Enterprise.com/Tecnic/SGI/OP/" />
        <add baseAddress="net.tcp://www.Enterprise.com/Tecnic/SGI/OP/" />           
      </baseAddresses>
    </host>
  </service>
</services>

我花了两天时间解决这个问题,但这是唯一对我有用的东西。