【问题标题】:The socket connection was aborted - CommunicationException套接字连接被中止 - CommunicationException
【发布时间】:2011-03-27 09:23:32
【问题描述】:

原文:

  • 我还以为是循环引用问题…………原来不是。
  • 问题源于根本没有配置服务配置。
  • 由于默认值非常低,发送大量数据会使服务崩溃。

场景:

  • 看来我的 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 类型的属性(这是一个自定义对象),并且该属性包含一个 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;
    }
}

【问题讨论】:

  • 如何从“套接字错误”到循环引用?您有任何可以添加到帖子中的错误消息吗?
  • 因为当我搜索错误消息时,我得到了很多关于循环引用的结果。此外,该错误仅在我尝试发送大量数据时发生,否则它可以正常工作。
  • 在我的情况下,这个错误是由应用程序池回收引起的。

标签: c# .net wcf exception-handling


【解决方案1】:

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

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

【讨论】:

  • 我遇到了这个错误,返回对象包含的属性包含小数超出范围和具有无效值的枚举。
  • 在没有.TableName 的情况下传递DataTable,或没有数据的空表(new DataTable())也可能导致此问题。
  • 我遇到了这个错误,根本原因是 WCF。当我从 WCF 切换出来时,问题就消失了。
  • 我知道这不适用于原始代码,但我遇到了这个错误,并发现问题出在我的 DataContract 对象上的 ReadOnly 属性上。我也给了他们所有的二传手,例如{得到;设置;},它工作正常
  • @GLewis 好收获!我不敢相信有人花了这么长时间才想出这个。我相应地更新了我的答案。
【解决方案2】:

该异常与循环引用无关,它只是纯粹的超时,因为您尝试通过网络传输大量数据。

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。

【讨论】:

  • 太棒了,你是对的,我的好人!
  • 该死,第二个链接失效了。
  • 第二个链接有镜像吗?
  • 添加了链接的缓存版本
【解决方案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);

【讨论】:

    【解决方案4】:

    这个问题也可能是由于您在使用完 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 语句中,所以调用了通道的最终处置。这样就可以防止由于通道没有被正确清理而发生的错误,看起来像这个错误。

    【讨论】:

      【解决方案5】:

      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】:

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

        【讨论】:

          【解决方案7】:

          在我的例子中,我试图用 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>
          

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-12-28
            • 2015-08-17
            • 1970-01-01
            • 2011-04-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多