此篇文章主要是基于http协议应用于大文件传输中的应用,现在我们先解析下wcf中编码器的定义,编码器实现了类的编码,并负责将Message内存中消息转变为网络发送的字节流或者字节缓冲区(对于发送方而言)。在接收方,编码会将一系列字节转变为内存中的消息

在wcf中有三个编码器

1、TextMessageEncodingBindingElement

文本消息编码器是所有的基于Http的绑定的默认编码器,并且是最关注互操作性的所有的自定义绑定的正确选择。即为请求/应答模式,此编码器读取和编码标准为SOAP1.1/SOAP1.2的文本消息,而不会对二进制数据进行任何特殊处理,如果消息的MessageVersion设置为None,则SOAP信封包装从输出中省略,只有正文内容进行序列化。

2、MtomMessageEncodingBindingElement

MTOM消息编码器是也是一个文本编码器,实现对二进制数据的特殊处理,默认情况下在任何标准绑定中都不会使用,也就是说需要我们自己定义(一般定义在wsHttpBinding中),因为它是一个严格按具体情况进行优化的实用工具,只有当二进制数据的量不超过某个阀值时,MTOM编码才具有优势,如果信息包含的二进制数据超过某个阀值,则这些数据会外部化消息信封之后的MIME部分

3、BinaryMessageEncodingBindingElement

二进制消息编码器是Net*绑定的默认编码器,当通信双方都基于WCF时,此编码器始终是正确的选择。二进制消息编码使用.NET二进制XML格式,该格式是XML信息集(Information Sets,Infosets)的Microsoft特定二进制表示法,与等效的xml1.0表示法相比产生的需求量通常较小,并将二进制数据编码为字节流

每个标准绑定都包括一个预配置编码器,因此默认情况下Net*前缀的绑定使用二进制编码(通过包括BinaryMessageEncodingBindingElement类),而BasicHttpBinding和WSHttpBing类则使用文本信息编码器(通过TextMessageEncodingBindingElement类)

通常,文本信息编码是要求互操作性的任意通信路径的最佳选择,也就是通用性比较高,而二进制消息编码则是其他任意通信路径的最佳选择。通常,对于当个消息而言,二进制编码生成的消息要小于文本编码,并且在通信会话期间消息大小会逐渐变得更小。于文本编码不同的是,二进制编码不需要对数据进行特殊处理(例如,使用Base64),当会字节表示为字节

如果数据无法分段,消息必须及时的方式传递或者当传输启动时数据为完全就绪,则应考虑启用流模式,而且只能对大型消息(带文本或者二进制)启用流模式

无法执行信息正文的数字签名,因为他们需要整个消息内容进行哈希算法。采用流模式的情况下,当构造和发送消息头时,内容尚未完全就绪,因此无法计算数字签名。

加密依赖于数字签名验证是否已经正确的重新构造数据

如果消息在传输过程中丢失,可靠的会话必须在客户端上缓冲已发送的消息以便可以重新传递,并且在将消息传递给服务实现之前必须在服务上保留信息以保证信息顺序。以备在未按顺序接受消息时可以按照正确的顺寻重新排列消息

下面我们通过一个上传文件的简单程序实现流文件的上传:

有几点我们需要注意:

1、在我们流文件上传的时候,需要定义文件的一些属性,这样我们就需要用消息契约代替数据契约方式

2、流文件上传的时候我们定义方法的时候只能保持一个参数,即消息契约。

第一步、新建文件消息契约

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.IO; namespace streamFileUp
{
/// <summary>
/// 消息契约(定义与SOAP消息相对应的强类型)
/// 因为我们用流传输,所以用消息契约代替传统的数据契约
///
/// </summary>
[MessageContract]
public class FileWrapper
{
/// <summary>
///SOAP的消息头这里即为标记文件的路径
/// </summary>
[MessageHeader]
public string FilePath;
/// <summary>
/// SOAP消息的内容,指定成员序列化正文中的元素
/// </summary>
[MessageBodyMember]
public Stream FileData;
}
/// <summary>
/// 返回结果
/// </summary>
[MessageContract]
public class result
{
[MessageBodyMember]
public bool returnresult;
}
}

第二步,定义服务契约

using System;
using System.ServiceModel; namespace streamFileUp
{
[ServiceContract]
public interface IStreamed
{
/// <summary>
/// 上传文件
/// </summary>
/// 1、支持数据流传输的绑定有:BasicHttpBding、NetTcpBinding和NetNamedPipeBinding
/// 2、数据流类型必须是可序列化的sream或MemorySream
/// 3、传递时消息体(Message Body)中不可能包含其他数据,即参数只能有一个streamFileUp.FileWrapper
/// <param name="fileWrapper">信息载体</param>
[OperationContract]
result UploadFile(FileWrapper fileWrapper);
}
}

第三步、实现类,注释很全,就不解释了

using System;
using System.Collections.Generic;
using System.IO;
using System.ServiceModel; namespace streamFileUp
{
public class Streamed : IStreamed
{
/// <summary>
/// 上传文件
/// </summary>
/// <param name="fileWrapper">streamFileUp.FileWrapper</param>
public result UploadFile(FileWrapper fileWrapper)
{
try
{
var sourceSream = fileWrapper.FileData;
var targetSream = new FileStream(fileWrapper.FilePath,
FileMode.Create,
FileAccess.Write,
FileShare.None);
var buffer = new byte[];
var count = ;
while ((count = sourceSream.Read(buffer, , buffer.Length)) > )
{
targetSream.Write(buffer, , count);
}
targetSream.Close();
sourceSream.Close();
}
catch (Exception)
{
return new result { returnresult = false };
}
return new result { returnresult = true };
}
}
}

第四步、我们采取自托管,新建服务

using System;
using System.ServiceModel; namespace streamFileUp
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(Streamed)))
{
host.Opened += delegate
{
Console.WriteLine("服务已经启动");
};
host.Open();
foreach (var endpoint in host.Description.Endpoints)
{
Console.WriteLine(endpoint.Address.ToString());
}
Console.ReadLine();
}
}
}
}

第五步,这里是我们的配置文件,晒一下,注释很详细,记住是配置流传输

<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<services>
<!--name 提供服务的类名-->
<!--behaviorConfiguraron 指定相关的行为配置 -->
<service name="streamFileUp.Streamed"
behaviorConfiguration="MessageBehavior">
<!--address - 服务地址-->
<!--binding - 通信方式-->
<!--contract - 服务契约-->
<!--bindingConfiguration - 指定相关的绑定配置-->
<endpoint
address="Message/Streamed"
binding="netTcpBinding"
contract="streamFileUp.IStreamed"
bindingConfiguration="StreamedBindingConfiguration" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:12345/Message/Streamed/"/>
<add baseAddress="net.tcp://localhost:54321/"/>
</baseAddresses>
</host>
</service>
</services> <behaviors>
<serviceBehaviors>
<behavior name="MessageBehavior">
<!--httpGetEnabled - 使用get方式提供服务-->
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors> <bindings>
<netTcpBinding>
<!--transferMode - 指示通道是使用流处理模式还是缓冲模式来传输请求和响应消息-->
<!--maxReceivedMessageSize - 在采用此绑定配置的通道上可接收的最大消息大小(单位:字节)-->
<!--receiveTimeout - 在传输引发异常之前可用于完成读取操作的时间间隔-->
<binding
name="StreamedBindingConfiguration"
transferMode="Streamed"
maxReceivedMessageSize=""
receiveTimeout="00:10:00" />
</netTcpBinding>
</bindings> </system.serviceModel> </configuration>

到此我们的服务端已经建立成功了,跑一下试试...

可以看到我们公开了两个服务地址,一个是net.tcp、一个是http...其实这里面http地址是引用服务的基地址,其传递方式还是采用

tcp方式的,一会我们通过客户端验证来下我们的推测。

下面我们开始新建客户端,来连接该服务:

第一步、新建类库,引用该服务,这里面有几点注意,在流的传输下我们客户端生成代码的时候服务地址是不能用上面的net.tcp...

我们需要引用http:......基地址生成:

第三步、实现客户端上传文件:

using System;
using System.Collections.Generic;
using System.ServiceModel; namespace client
{
class Program
{
static void Main(string[] args)
{
///自定义绑定
string strAddress = "net.tcp://localhost:54321/Message/Streamed";
ChannelFactory<ServiceFileUp.IStreamed> factory = new ChannelFactory<ServiceFileUp.IStreamed>("NetTcpBinding_IStreamed", new EndpointAddress(strAddress));
ServiceFileUp.IStreamed service = factory.CreateChannel(); string filePath = @"G:\wcf学习测试案例\wcf大型数据传输\1.jpg";
string newFilePath = @"G:\wcf学习测试案例\wcf大型数据传输\2.jpg"; System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); //定义观察者 watch.Start();
ServiceFileUp.result returnResult = service.UploadFile(getSreamFromFile(filePath, newFilePath));
watch.Stop(); if (returnResult.returnresult)
{
Console.WriteLine("上传成功,上传时间为:" + watch.ElapsedMilliseconds);
Console.ReadLine();
}
else
{
Console.WriteLine("上传失败");
Console.ReadLine();
}
}
/// <summary>
/// 流数据上传文件
/// </summary>
/// <param name="file">源文件地址</param> public static ServiceFileUp.FileWrapper getSreamFromFile(string file, string newFilePath)
{
ServiceFileUp.FileWrapper myFileFw = null;
try
{
var sr = new System.IO.FileStream(
file, System.IO.FileMode.Open);
ServiceFileUp.FileWrapper oneFW = new ServiceFileUp.FileWrapper()
{
FilePath = newFilePath,
FileData = sr
};
myFileFw = oneFW;
Console.WriteLine("文件大小为:"+sr.Length.ToString());
//sr.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return myFileFw;
} }
}

我们在G盘下面放了一个jpg文件,然后通过上传同样的在该目录下存入我们刚才上传的文件,这里我们顺便监听了一下上传该文件需要的时间

下面晒一下结果:

说明文件上传是成功的,下面我们变换一种方式,以上方式我们是自定义了net.tcp地址的方式实现了文件的上传,我们改变一下直接用

http方式看看文件上传时候会变慢:

看运行结果:

呵呵...同样能实现上传的功能,但是性能的落后于基地址赋值地址,当然本身client方式就是通过ChannelFactory工厂创建,性能有所耗损是必然的,这里同样告诫我们:

在大文件传输的时候我们最好是通过自定义地址实现客户端配置,当然我们现在只是传递了一个简单的图片,对于大文件的上传我们需要更多的配置和性能优化。

来自:http://www.cnblogs.com/zhijianliutang/archive/2011/11/28/2265989.html

转:wcf大文件传输解决之道(2)的更多相关文章

  1. 转:wcf大文件传输解决之道(1)

    首先声明,文章思路源于MSDN中徐长龙老师的课程整理,加上自己的一些心得体会,先总结如下: 在应对与大文件传输的情况下,因为wcf默认采用的是缓存加载对象,也就是说将文件包一次性接受至缓存中,然后生成 ...

  2. WCF大文件传输【转】

    http://www.cnblogs.com/happygx/archive/2013/10/29/3393973.html WCF大文件传输 WCF传输文件的时候可以设置每次文件的传输大小,如果是小 ...

  3. WCF大文件传输服务

    由于项目需要,自己写一个基于WCF的大文件传输服务雏形.觉得有一定的参考价值,因此放在网上分享. 目前版本为v1.1特点如下: 1.文件传输端口为18650 2.上传和下载文件 3.支持获取文件传输状 ...

  4. WCF大文件传输

    WCF传输文件的时候可以设置每次文件的传输大小,如果是小文件的时候,可以很方便的将文件传递到服务端,但是如果文件比较大的话,就不可取了 遇到大文件的话可以采取分段传输的方式进行文件传输 思路: 1.客 ...

  5. WCF 大文件传输配置

    <bindings> <webHttpBinding> <!--这个是接收大数据加的,设置WCF服务器端数据接收上限参数,此处单位字节,故2147483647字节==2G ...

  6. Nginx集群之WCF大文件上传及下载(支持6G传输)

    目录 1       大概思路... 1 2       Nginx集群之WCF大文件上传及下载... 1 3       BasicHttpBinding相关配置解析... 2 4       编写 ...

  7. 大文件传输 分片上传 上传id 分片号 授权给第三方上传

    https://www.zhihu.com/question/39593108 作者:ZeroOne链接:https://www.zhihu.com/question/39593108/answer/ ...

  8. 【转】Windows2008上传大文件的解决方法(iis7解决上传大容量文件)

    2008上传大文件的解决方法:http://wenku.it168.com/d_000091739.shtml 2003上传大文件的解决方法:http://tech.v01.cn/windowsxit ...

  9. 利用Socket进行大文件传输

    分类: WINDOWS 最近接触到利用socket进行大文件传输的技术,有些心得,与大家分享.首先看看这个过程是怎么进行的(如下图):      所以,我们需要三个socket在窗体加载的时候初始化: ...

随机推荐

  1. 更改配置:远程访问gitlab的postgresql数据库

    作为这篇文章的补充: 将gitlab中的postgresql数据库开通远程访问 https://www.cnblogs.com/andy9468/p/10609682.html 替代(二)中的2.3. ...

  2. lsof 命令

    [root@localhost ~]# lsof COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME init root cwd DIR , / in ...

  3. JS页面跳转代码怎么写?总结了5种方法

    我们在建站时有些链接是固定的,比如客服咨询链接,一般是第三方url,如果直接加上去不太专业,那么就想着用站内的页面做跳转,跳转用js比较多,那么JS页面跳转代码怎么写呢?ytkah在网上搜索了一下,大 ...

  4. MySQL 5.7 的SSL加密方法

    MySQL 5.7 的SSL加密方法 MySQL 5.7.6或以上版本 (1)创建证书开启SSL验证--安装opensslyum install -y opensslopenssl versionOp ...

  5. RCNN

    [Rich feature hierarchies for accurate object detection and semantic segmentation] 技术路线:selective se ...

  6. mysql的查询

    1.单表查询 单表查询的语法 SELECT 字段1,字段2... FROM 表名 WHERE 条件 GROUP BY field HAVING 筛选 ORDER BY field LIMIT 限制条数 ...

  7. Django 框架 数据库操作2

    一.ORM的操作方法总结 get(self, *args, **kwargs): # 获取单个对象 def one_get(request): #直接得到一个表对象,也就是表记录 如果得到多个会报错 ...

  8. [LeetCode] 130. Surrounded Regions_Medium tag: DFS/BFS

    Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A reg ...

  9. PHP处理大文件下载

    <?php /** * Created by PhpStorm. * User: Kung * Date: 15-10-21 * Time: 下午8:00 */ set_time_limit(0 ...

  10. MySQL--3约束和修改数据表总结