第十一讲:大消息处理

代码

https://yunpan.cn/cPns5DkGnRGNs   密码:3913

从这一节课开始,不是特殊的Demo,我们不再贴实例Demo的图片了,直接去网盘找响应的项目看



大型消息传送

大消息可能来源于某些场合,比如传输大文件,或者包含了二进制附件作为消息的一部分。消息本身也可能变得很大,例如当大量记录在客户和服务之间传输的时候。大型消息在传送时,会有很多需要考虑的因素,而不仅仅是简单地考虑适应消息的大小要求。当处理大消息时,就应该控制在现有效载荷规模,以减少带宽占用和处理开销,并分流客户和服务的内存消费。

上一节课我们更改了配置,以至于增大接受消息的大小。可这仅仅是接受大小,并没有控制处理开销以及分流

控制有效负载大小

消息大小受你选择的消息编码方式的影响:

BinaryMessageEncoder,TextMessageEncoder, MtomMessageEncoder.

WEB 服务绑定的默认编码方式是Text,但是WEB服务绑定也支持Mtom编码方式。非HTTP绑定对应的默认编码方式是Binary。

BinaryMessageEncoder:

用一种紧凑二进制格式来串行化消息,它产生的消息的大小是3种编码方式中最小的体积。Soap1.2消息格式仍然被保留,不过其串行化格式不是可互操作的( 仅限于.NET平台之间通信).

TextMessageEncoder:

用SOAP1.1或SOAP1.2那样的文本格式来串行化消息。这一格式是可互操作的。不过消息大小却要比二进制编码大得多。而且,任何二进制数据,比如,字节数组都是base64编码以便使用XML来表示,这就使得消息规模最大可以膨胀33%

MtomMessageEncoder:

这是一个可互操作的方式(跨平台的编码)来改善大规模二进制数据在SOAP消息的传输性能具有重大的意义。二进制数据的串行化已经是紧凑了,不过,任何时候,当你想要基于HTTP来传输大量的二进制数据时,你就应该考虑激活绑定中的MTOM编码。



我们看这个Demo,这个Demo 与之前的不太一样,前面我们都是以 控制台应用程序以及WinFrom 的方式 寄宿的服务器。

这个Demo将使用IIS方式去寄宿服务器。

创建项目的方法

[ 11-01 ]

项目结构:

[ 11-02 ]

WcfService就是服务端

IService1.cs 为服务器契约

[ 11-03 ]

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Runtime.Serialization;
 5 using System.ServiceModel;
 6 using System.ServiceModel.Web;
 7 using System.Text;
 8
 9 namespace WcfService
10 {
11
12
13
14     // 注意: 如果更改此处的接口名称 "IService1",也必须更新 Web.config 中对 "IService1" 的引用。
15     [ServiceContract]
16     public interface IService1
17     {
18         /// <summary>
19         /// 上传文件
20         /// </summary>
21         /// <param name="path">文件目标路径</param>
22         /// <param name="fileData">文件字节数组</param>
23         [OperationContract]
24         void UploadFile(string path, byte[] fileData);
25     }
26
27
28 }

Service1.svc为服务器契约的实现

[ 11-04 ]

 1 using System;
 2 using System.Collections.Generic;
 3 using System.IO;
 4 using System.Linq;
 5 using System.Runtime.Serialization;
 6 using System.ServiceModel;
 7 using System.ServiceModel.Web;
 8 using System.Text;
 9
10 namespace WcfService
11 {
12     // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
13     // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。
14
15
16
17     public class Service1 : IService1
18     {
19         /// <summary>
20         /// 上传文件
21         /// </summary>
22         /// <param name="path">文件目标路径</param>
23         /// <param name="fileData">文件字节数组</param>
24         public void UploadFile(string path, byte[] fileData)
25         {
26             FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
27             fs.Write(fileData, 0, fileData.Length);
28             fs.Flush();
29             fs.Close();
30         }
31     }
32
33 }

然后Web.config

[ 11-05 ]

 1   <system.serviceModel>
 2     <services>
 3       <service name="WcfService.Service1" behaviorConfiguration="WcfService.Service1Behavior">
 4         <!-- Service Endpoints -->
 5         <!--这里的address不需要配置,因为我们的这个项目是寄宿在IIS中的项目,所以address就默认是IIS指定的地址-->
 6         <endpoint address="" binding="wsHttpBinding" contract="WcfService.IService1" bindingConfiguration="MtomBindingConfiguration">
 7           <!--
 8               部署时,应删除或替换下列标识元素,以反映
 9               在其下运行部署服务的标识。删除之后,WCF 将
10               自动推导相应标识。
11           -->
12           <identity>
13             <dns value="localhost"/>
14           </identity>
15         </endpoint>
16         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
17       </service>
18     </services>
19     <behaviors>
20       <serviceBehaviors>
21         <behavior name="WcfService.Service1Behavior">
22           <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点-->
23           <serviceMetadata httpGetEnabled="true"/>
24           <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息-->
25           <serviceDebug includeExceptionDetailInFaults="false"/>
26         </behavior>
27       </serviceBehaviors>
28     </behaviors>
29     <bindings>
30       <wsHttpBinding>
31         <!--messageEncoding消息编码方式  maxReceivedMessageSize接收最大字节数[ 5000000 就是5M ]  receiveTimeout接收超时时间-->
32         <binding name="MtomBindingConfiguration" messageEncoding="Mtom" maxReceivedMessageSize="5000000" receiveTimeout="00:10:00">
33           <readerQuotas maxArrayLength="5000000"/>
34         </binding>
35       </wsHttpBinding>
36     </bindings>
37   </system.serviceModel>

Web为客户端 首先需要引用上面的服务

然后页面

[  11-06 ]

代码

[ 11-07 ]

 1         /// <summary>
 2         /// 上传
 3         /// </summary>
 4         /// <param name="sender"></param>
 5         /// <param name="e"></param>
 6         protected void btnUpload_Click(object sender, EventArgs e)
 7         {
 8             WCFService.Service1Client proxy = new Web.WCFService.Service1Client();
 9             var length = file.PostedFile.ContentLength;
10             var bytes = new byte[length];
11             file.PostedFile.InputStream.Read(bytes, 0, length);
12             try
13             {
14                 proxy.UploadFile(txtDestination.Text + Path.GetFileName(file.PostedFile.FileName), bytes);
15                 Page.ClientScript.RegisterStartupScript(typeof(Page), "js", "alert(‘上传成功‘);", true);
16             }
17             catch (Exception ex)
18             {
19                 Page.ClientScript.RegisterStartupScript(typeof(Page), "js", "alert(‘" + ex.ToString() + "‘);", true);
20             }
21             proxy.Close();
22         }

客户端的AppConfig文件

[ 11-08 ]

 1   <system.serviceModel>
 2     <!--<bindings>
 3             <wsHttpBinding>
 4                 <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
 5                     openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
 6                     bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
 7                     maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
 8                     messageEncoding="Mtom" textEncoding="utf-8" useDefaultWebProxy="true"
 9                     allowCookies="false">
10                     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
11                         maxBytesPerRead="4096" maxNameTableCharCount="16384" />
12                     <reliableSession ordered="true" inactivityTimeout="00:10:00"
13                         enabled="false" />
14                     <security mode="Message">
15                         <transport clientCredentialType="Windows" proxyCredentialType="None"
16                             realm="" />
17                         <message clientCredentialType="Windows" negotiateServiceCredential="true"
18                             algorithmSuite="Default" establishSecurityContext="true" />
19                     </security>
20                 </binding>
21             </wsHttpBinding>
22         </bindings>-->
23     <bindings>
24       <wsHttpBinding>
25         <!--sendTimeout 发送的时间   messageEncoding消息编码方式  -->
26         <binding name="WSHttpBinding_IService1" sendTimeout="00:10:00" messageEncoding="Mtom">
27           <!--readerQuotas发送最大字节数 [ 5000000= 5M ]-->
28           <readerQuotas maxArrayLength="5000000" />
29         </binding>
30         <binding name="WSHttpBinding_IService11" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
31                  bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
32                  messageEncoding="Mtom" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
33           <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
34           <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
35           <security mode="Message">
36             <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
37             <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" />
38           </security>
39         </binding>
40       </wsHttpBinding>
41     </bindings>
42     <client>
43       <endpoint address="http://localhost:1217/Service1.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService11" contract="WCFService.IService1"
44                 name="WSHttpBinding_IService11">
45         <identity>
46           <dns value="localhost" />
47         </identity>
48       </endpoint>
49     </client>
50   </system.serviceModel>

然后我们进行 测试,注意 首先需要启动服务端

[ 11-09 ]

[ 11-10 ]

然后再运行Web项目的  Default.aspx

注意:一定要先启用Service1.svc 服务,并且Web端的Web.config 中 endpoint 的 address 一定是  Service1.svc服务的地址

[ 11-11 ]



除了选择编码格式以外,你还可以采用压缩方式,以进一步减少客户和服务之间消息载荷传输的开销。

DEMO :使用MTOM来处理带有二进制数据的大型消息

为大文件传输激活消息流(使用流数据则不用把数据都加载到内存后才传输,减少内存开销)

可以看 云盘上面的      第十一讲  大消息处理   /  代码   /  2.消息流 项目

看完了代码记得 测试一下,传输一个 比较大的 文件,一定要使用消息流的这种方式。

查看在传输的过程中  注意观察 D盘传输的文件 大小变化。

文件不是一次性传入D盘的,也不是将所有文件加载到内存再复制到D盘的,而是 从C盘 传 到D 盘的 文件是经过流,过程中 D盘所传的文件大小是一点一点增加的。

从这个Demo 中我们可以 看出

在默认的情况下,消息在发送和接受的过程中是需要由服务模型来进行缓冲存储的。这样会给服务器内存带来很大的压力,尤其是当多个并发请求同时被处理时。在客户端,当很大的文件被传输和缓存时,这也会带来局部失衡。  减少内存消耗的一个选择,是像消息流操作实例那样,用消息流的方式发送大消息。这样就防止了服务模型将整个消息读进内存,并且允许消息的接收者(客户端)控制消息流的读入方式。对于大的文件来说,这可能意味着直接将消息写入磁盘。

我们说一下 关于 服务端配置  消息大小限额  的 相关节点:

有一些设置影响到服务模型处理消息的方式;有一些特殊设置限制了字符串的长度,数组的长度,对象,XML嵌套和整个消息的大小;其他设置控制了缓冲处理的方式,并作为内存占用的分流和垃圾回收开销。

MaxBufferPoolSize:预先分配缓冲区以处理到达请求,而不是从内存堆中分配.

MaxBufferSize:限制到达消息的缓冲区压力。当对消息被缓存时,其大小必须匹配.

MaxReceivedMessageSize.而对于消息流,缓冲区长度会比较小从而减少缓存消耗.

MaxReceivedMessageSize:限制服务和客户受到的整个串行化消息的大小,这与内存消费无关——反串行化消息时或许需要额外的内存.

下面的属性是阅读器限额---是ReaderQuotas绑定属性一部分,影响XML阅读器处理消息的方式:

MaxArrayLength:限制字符串和其他数组的长度,包括大型二进制传输的字节数组.

MaxBytesPerRead:限制每一个阅读操作的字节数组.

MaxDepth:限制XML元素的嵌套深度.

MaxNameTableCharCount:限制阅读器名称表的大小。名称表包括XML消息流中的前缀和命名空间.

MaxStringContentLength:限制字符串元素的长度.最后一个行为是数据契约串行化限额,这个限额通过一个行为提供,与绑定属性相对:MaxItemsInObjectGraph

限制串行化期间对象图中可供展现的对象数目。如果你传送带有很多嵌套引用类型的对象,那么,你就超出了这个限额.

它们都是局部设置,意思是,它们不包含在服务描述中,因此不能够为客户所知晓,单客户可以分流限额以适应自身的需要,事实上,客户代理依据客户限额来验证消息,使其不会发送超过限额的消息来麻烦服务.

消息流对大文件传输很有用。消息流在发送和接收时不必缓存消息,这使得发送方提供消息流对象而接收方增量式读入它成为可能。这样做减少了内存消耗,尤其是,如果采用文件流方式,就使得服务器端的文件直接以流方式到达客户一端的文件中成为可能。对于

服务器来说,这样做有很多好处,因为它将放置服务器将文件的整个实例装入内存用于并发请求,而原来这样做会很快导致内存异常,从而导致其他任何后续请求不能够得到服务。对于客户来说,当文件很大时,这样做也很有用,因为他们有可能没有足够的内存来缓存整个文件.

为了完全支持消息流,需要满足一些基本要求:

1:操作接收或返回一个单一Stream类型

2:服务契约的绑定协议必须支持消息流

3:必须在绑定中激活消息流.

激活消息流:

你可以在如下的绑定中激活消息流:NetNamedPipeBinding,NetTcpBinding(用于企业级局域网)和BasicHttpBinding(用于互联网).

这是通过设置绑定的TransferMode属性来实现的,该属性的选项如下所示:

Buffered:这是一个默认值,没有消息流.

Streamed:在绑定的请求和回复上激活消息流

StreamedRequest:只在请求方向上激活消息流

StreamedResponse:只在回复方向上激活消息流.

总结

1:优先考虑WSHttpBinding用于WEB服务端点。WSHttpBinding的配置将会随着协议支持会话、可靠通信、事务和安全性的不同变化。(将BasicHttpBinding用于向后兼容,只兼容老的WEB服务,如果需要传输大文件的话也是 有可能 需要考虑使用BasicHttpBinding绑定方式,因为它可以使用Streame 消息流)

2:将NetNamedPipeBinding用于同一台机器上的通信过程。使用NetTcpBinding来支持跨机器边界的调用.

3:如果需要支持基于HTTP的回叫(HTTP方式的双工通信),就用WSDualHttpBinding。

4:留心一下期望的消息有效负载大小,并相应地设置绑定配置。如果你在使用文件传输时,将MTOM协议用于基于HTTP和消息流的大的二进制负载,可以减少内存消耗.

时间: 2024-10-25 13:13:09

第十一讲:大消息处理的相关文章

《上古天真论》第十一讲文字版

上古天真论篇第十一讲 主讲:徐文兵  主持:梁  冬 播出时间:2009-02-21  23:00—24:00 经文:帝曰:有其年已老而有子者,何也?岐伯曰:此其天寿过度,气脉常通,而肾气有余也.此虽有子,男不过尽八八,女不过尽七七,而天地之精气皆竭矣.帝曰:夫道者,年皆百数,能有子乎?岐伯曰:夫道者,能却老而全形,身年虽寿,能生子也. 梁冬:是的,重新发现,中医太美.大家好,欢迎收听今天的<国学堂>.我是梁冬,对面的依然是徐文兵.徐小周老师.欢迎您. 徐文兵:梁冬好,听众朋友们,大家好. 梁

第二十一讲 经典动态图表实现原理

??在制作动态图表之前,首先需要学习如何定义表格区域的名称,方便后面的引用.方法是:公式-定义的名称:定义名称,填写名称和引用位置,引用位置可以使用公式. 2. 表单控件 ??动态图表的实现首先可能用到的工具是表单控件,打开文件-选项:自定义功能区-右侧:主选项卡-勾选开发工具,添加开发工具到Excel选项卡中. ??动态图表可能用到的表单控件有两个:复选框和滚动条,选择开发工具-控件:插入:复选框/滚动条. ??复选框的用法是:定义名称:=IF(复选框要链接的单元格,要选择的数据区域,空白数据

逆向知识十一讲,识别函数的调用约定,函数参数,函数返回值.

逆向知识十一讲,识别函数的调用约定,函数参数,函数返回值. 在反汇编中,我们常常的会看到各种的函数调用,或者通过逆向的手段,单独的使用这个函数,那么此时,我们就需要认识一下怎么识别函数了. 一丶识别__cdecl 函数(俗称C Call),函数参数,函数返回值 首先写一个C Call的函数 1.返回值 int类型, 参数int 类型 高级代码: int __cdecl MyAdd(int a,int b) { return a + b; } int main(int argc, char* ar

从大数据菜鸟走上大师的历程 Scala 第十一讲 extends

子类继承父类 要完成父类参数的填充 class Person(val name : String ,val age : Int) { println("father's constructor")   val Class = "first class "   def read = "10 hours"   override def toString = "I am a good person" } class Stu(name

第十一讲:软考中高项11_法律法规、标准规范、职业道德

一.法律法规和标准规范1.中国标准划分为哪四个层次?要求最低的是哪个? 国家标准.行业标准.地方标准.企业标准 要求最低的是企业标准 2.国家标准的制订程序包括哪些? 前期准备.立项.起草.征求意见.审查.批准.出版.复审.废止. 3.ISO标准每几年复审一次?我国国家标准的有效期几年复审一次? ISO标准每五年夏审一次,国家标准一般有效期五年. 4.请说明如下是什么标准?GB.GB/T.GB/Z.GJB? GB:强制性国家标准 GB/T:推荐性国家标准 GB/Z:国家标准指导性技术文件 GJB

第七十一讲:Android的单元测试类

我们应当努力奋斗,有所作为.这样,我们就可以说,我们没有虚度年华,并有可能在时间的沙滩上留下我们的足迹.--拿破伦一世 本讲内容:单元测试类 在Android应用开发过程中进行单元测试,个人在做项目的过程中,觉得单元测试很有必要,以保证我们编写程序的正确性. 一.单元测试步骤 : 第一步:在AndroidManifest.xml中的 <application></application>里面添加 <uses-library android:name="android

第十一讲.oc学习补充(description方法,)

一.description方法的使用 1.默认的description方法 NSLog函数一旦发现用%@输出某个OC对象时,就会调用这个对象的description方法(这个方法返回值是NSString类型,是OC中的字符串类型),并且将description方法返回的字符串代替%@的位置进行输出. * description方法的默认实现是返回这样的格式:<类名: 对象的内存地址>,因此上面代码的输出结果为: 2.重写description方法 description方法的默认实现是返回类名

Unity3D教程宝典之Shader篇:第十一讲剔除及深度测试

转载自风宇冲Unity3D教程学院 Culling阴影面剔除 Culling阴影面剔除是一种优化技术.所有的多边形都有正反两面,而你永远只能看见其中一面,不信的话拿张纸板或者一面镜子看看你能不能同时看到两面.通常多边形面向屏幕里面的背面,我们看不见,所以会将该面剔除. Cull Off 关闭阴影面剔除 Cull Back 剔除背面 Cull Front 剔除正面 Depth Testing深度测试 Depth Testing:深度测试,也叫深度缓冲.只有最靠近观察者的物体会被绘制.深度即Z,该值

第十一讲:面向对象编程(六)

玉不琢,不成器:人不学,不知道. --礼记·学记 本讲内容:接口 Java中只支持单继承,即一个类只能有一个父类.为了提供类似多重继承的功能,Java提供了接口(Interface)机制.但接口不仅仅是为了解决多重继承问题才出现的.接口拥有多重继承的好处,而且没有多重继承的缺点---多重继承的缺点全部来源于实现全部继承,关键在于接口只有abstract(默认.不用写)方法和常量. 譬如下面例子:有些动物和不能和人亲近玩耍的,不能继承. <span style="font-size:18px