【问题标题】:NetTCP and binary transferNetTCP 和二进制传输
【发布时间】:2011-08-19 12:26:02
【问题描述】:

我有一个带有 HTTP 绑定的 WCF 服务,它返回 500k 大小的数据集。 使用 WCF 默认日志记录时,我可以看到每条消息正在传输的消息和数据

  <system.serviceModel>
    <!-- add trace logging -->
    <diagnostics wmiProviderEnabled="true">
      <messageLogging
           logEntireMessage="true"
           logMalformedMessages="true"
           logMessagesAtServiceLevel="true"
           logMessagesAtTransportLevel="true"
           maxMessagesToLog="3000"
       />
    </diagnostics>

    ....

  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add type="System.Diagnostics.DefaultTraceListener" name="Default">
            <filter type="" />
          </add>
          <add initializeData="c:\nettcpTestLOCALToTEST.xml" type="System.Diagnostics.XmlWriterTraceListener"
            name="messages">
            <filter type="" />
          </add>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

重点是,我正在寻找一种方法来减少服务器和客户端之间的流量,并且有人告诉我 NetTCP 正在传输二进制数据?对吗?

我已经使用 NetTCPBinding 设置了一个测试场景,当我在客户端读取 WCF 时,响应消息包括整个数据集架构和 XML 格式的数据。它只是序列化以便可以写入日志,还是这条消息是二进制传输的?

使用 NetTCP 绑定传输的数据量是否小于使用 HTTPBinding 传输的数据量?是文本还是二进制?

提前感谢

【问题讨论】:

    标签: wcf nettcpbinding


    【解决方案1】:

    是的,消息将被传输二进制,但序列化器(我假设为 Datacontractserializer)将以 XML 格式序列化数据:

    使用 DataContractSerializer 类将类型的实例序列化和反序列化为 XML 流或文档

    DataContractSerializer 来自文档:

    默认情况下,NetTcpBinding 会生成一个运行时通信堆栈,它使用传输安全、TCP 进行消息传递和二进制消息编码。此绑定是一个适当的系统提供的选择,用于通过内联网进行通信。

    NetTcpBinding MSDN

    如果您选择实现 ISerializable,您也可以使用 WCF,但您必须实现 DataContractResolver 来解析类型:如果客户端“知道”类型(例如,您将它们放入 dll 并将它们添加到客户端 -应用程序)您可以使用以下示例代码(对不起,我只在 F# 中使用它,但您应该会发现它很容易翻译) 这应该以更紧凑的形式产生序列化。

    
    
    type internal SharedTypeResolver() =
        inherit System.Runtime.Serialization.DataContractResolver()
    
        let dict = new Xml.XmlDictionary()
    
        override this.TryResolveType(t : Type, declaredT : Type, knownTypeResolver : System.Runtime.Serialization.DataContractResolver, typeName : Xml.XmlDictionaryString byref, typeNamespace : Xml.XmlDictionaryString byref) =
            typeNamespace = dict.Add(t.Assembly.FullName)
            typeName = dict.Add(t.FullName)
            true
    
        override this.ResolveName(typeName : string, typeNamespace : string, declaredType : Type, knownTypeResolver : System.Runtime.Serialization.DataContractResolver) =
            let res = knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null)
            if res = null then Type.GetType(typeName + ", " + typeNamespace) else res
    

    PS:在 C# 中发现相同:

    
        public class SharedTypeResolver : DataContractResolver
        {
            #region Overrides of DataContractResolver
    
            /// 
            /// Override this method to map a data contract type to an xsi:type name and namespace during serialization.
            /// 
            /// 
            /// true if mapping succeeded; otherwise, false.
            /// 
            /// The type to map.The type declared in the data contract.The known type resolver.The xsi:type name.The xsi:type namespace.
            public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
            {
                if (!knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace))
                {
                    var dict = new XmlDictionary(); // nice trick to get the right type for typeName
                    if (type != null)
                    {
                        typeNamespace = dict.Add(type.Assembly.FullName);
                        typeName = dict.Add(type.FullName);
                    }
                    else
                    {
                        typeNamespace = dict.Add("noAss");
                        typeName = dict.Add("noType");
                    }
                }
                return true;
            }
    
            /// 
            /// Override this method to map the specified xsi:type name and namespace to a data contract type during deserialization.
            /// 
            /// 
            /// The type the xsi:type name and namespace is mapped to. 
            /// 
            /// The xsi:type name to map.The xsi:type namespace to map.The type declared in the data contract.The known type resolver.
            public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
            {
                return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ??
                       Type.GetType(typeName + ", " + typeNamespace);
            }
    
    

    (请注意:stackoverflow 不喜欢 F# 中的赋值运算符“

    
            private static void AddResolver(OperationDescription operationDescription)
            {
                if (operationDescription == null)
                    throw new ArgumentNullException();
    
                var serializationBehavior = operationDescription.Behaviors.Find();
                if (serializationBehavior == null)
                {
                    serializationBehavior = new DataContractSerializerOperationBehavior(operationDescription);
                    operationDescription.Behaviors.Add(serializationBehavior);
                }
                serializationBehavior.DataContractResolver = new SharedTypeResolver();
            }
    
    

    将此用于:

    
    
                var contrDescription = _host.Description.Endpoints[0].Contract;
                var description= contrDescription.Operations.Find("MyServiceMethod");
                AddResolver(description);
    
    
    

    用您的服务方法的名称替换“MyServiceMethod”(按方法调用或遍历所有方法)

    【讨论】:

    • 谢谢!但是如果我不实现你的解析器类,通过网络传输的数据是否仍然少于使用 HttpBinding 的数据?
    • 如果没有解析器,您的客户将不知道如何处理数据传输(但请尝试:我写这篇文章已经有一段时间了 - 也许他们会在您的程序集中寻找已知类型 - 但我对此表示怀疑因为一开始你必须在你的合同定义中命名额外的“KnownTypes”)
    • 这里有一篇关于这个问题的好文章:blogs.msdn.com/b/youssefm/archive/2009/06/05/…(我想我可以把这个链接起来……我的代码直接来自这篇文章;))
    • 我做了一些测试,结果表明从 WSHTTP 切换到 NetTCP 后流量减少了 30%。我实际上希望减少更多,因为它现在是二进制传输:/
    • 我忘了说这是一个 .net 3.5 应用程序。你的文章是4.0左右?
    猜你喜欢
    • 1970-01-01
    • 2011-01-06
    • 1970-01-01
    • 1970-01-01
    • 2017-01-22
    • 2012-08-27
    • 2017-07-01
    • 2015-04-17
    • 1970-01-01
    相关资源
    最近更新 更多