zoukankan      html  css  js  c++  java
  • 日志 20071213(WCF,C#对网络流的操作)

    1.对于按照Stream方式来进行传输的WCF应用,有一个非常重要的限制,那就是调用参数或者返回值只能有一个,并且必须是Stream类型。比如,下面的方法签名都是能支持Stream的:
    void StreamIn(Stream input)   //  void StreamIn(Stream input, int additional)则不行
    Stream StreamOut()  // Stream StreamOut(out string additional)则不行
    Stream StreamInAndOut(Stream input)
    void StreamInAndOut(Stream input, out Stream result)
    如果不满足这个限制,整个处理模型会自动转回成Buffered的模式。

    2.自己尝试在WCF中用Streamed的方式来读取文件,涉及到对流的操作问题,在网上找到一篇不错的文章(http://hi.baidu.com/czyblues/blog/item/8b5c3b0e268413c87bcbe19c.html),摘录一小段如下:

    你平时是怎么读取文件的?使用流读取。是的没错,C#给我们提供了非常强大的类库(又一次吹捧了.NET一番),里面封装了几乎所有我们可以想到的和我们没有想到的类,流是读取文件的一般手段,那么你真的会用它读取文件中的数据了么?真的能读完全么?通常我们读取一个文件使用如下的步骤: 1、声明并使用File的OpenRead实例化一个文件流对象,就像下面这样
    FileStream fs = File.OpenRead(filename);
    或者 FileStream fs = FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
    2、准备一个存放文件内容的字节数组,fs.Length将得到文件的实际大小,就像下面这样 byte[] data = new byte[fs.Length];
    3、哇!开始读了,调用一个文件流的一个方法读取数据到data数组中 fs.Read (data, 0, data.Length); 呵呵!我们只写了3句就可以把文件里面的内容原封不动的读出来,真是太简洁了!可以这段代码真的能像你预期的那样工作么?答案是:几乎可以!在大部分情况下上面的代码工作的很好,但是我们应该注意Read方法是有返回值的,既然有返回值那么一定有其道理,如果按照上面的写法完全可以是一个没有返回值的函数。我想返回值的目的是,为了给我们一个机会判断实际读取文件的大小,从而来判断文件是否已经完全读完。所以上面的代码不能保证我们一定读完了文件里面的所有字节(虽然在很多情况下是读完了)。
     
    特别当我们要处理的流是网络流的时候,我们根本得不到它的Length属性,所以我们要使用下面这样的方法,先开辟一个初始缓存区,然后不停的用流向缓冲区写入。当缓冲区用完了而流还没到结束的时候,加大缓冲区的长度,直到流的结尾。代码如下:

    //对于网络流,我们无法获取其长度。
    //故而从网上找了这个方法,以一种使用指定缓存长度的方式读取流。
    public static byte[] Read2Buffer(Stream stream, int BufferLen)
    {
        
    // 如果指定的无效长度的缓冲区,则指定一个默认的长度作为缓存大小
        if (BufferLen < 1)
        
    {
        BufferLen 
    = 0x8000;
        }


        
    // 初始化一个缓存区
        byte[] buffer = new byte[BufferLen];
        
    int read = 0;
        
    int block;

        
    // 每次从流中读取缓存大小的数据,直到读取完所有的流为止
        while ((block = stream.Read(buffer, read, buffer.Length - read)) > 0)
        
    {
        
    // 重新设定读取位置
        read += block;

        
    // 检查是否到达了缓存的边界,检查是否还有可以读取的信息
        if (read == buffer.Length)
        
    {
            
    // 尝试读取一个字节
            int nextByte = stream.ReadByte();

            
    // 读取失败则说明读取完成可以返回结果
            if (nextByte == -1)
            
    {
            
    return buffer;
            }


            
    // 调整数组大小准备继续读取
            byte[] newBuf = new byte[buffer.Length * 2];
            Array.Copy(buffer, newBuf, buffer.Length);
            newBuf[read] 
    = (byte)nextByte;

            
    // buffer是一个引用(指针),这里意在重新设定buffer指针指向一个更大的内存
            buffer = newBuf;
            read
    ++;
        }

        }


        
    // 如果缓存太大则使用ret来收缩前面while读取的buffer,然后直接返回
        byte[] ret = new byte[read];
        Array.Copy(buffer, ret, read);
        
    return ret;
    }

    3.经过自己今天的试验,对于怎么开发Smart Vendee Client的大文件下载以及断点续传,已经基本上有谱儿了,明天就可以开始编码了,现在在这里把一些比较关键的要点列一列:
    (1)超过“一定大小”的文件分块儿下载
    (2)所谓“一定大小”指的是按照用户的历史下载速度平均值乘以一个时间值
    (3)时间值在客户端的配置文件中设定,初定为10s
    (4)用户的历史下载速度靠我们的系统来进行统计。也就是每次进行文件下载的时候都算一下下载速度,然后和历史下载速度进行算术平均,得出新的下载速度经验值。
    (5)如果文件的大小小于“一定大小”,不采用MTOM编码,仍采用Text编码;否则,对完整分块儿采用MTOM编码,对最后一个不规则块采用Text编码。(主要是Mtom编码需要有额外的分包开销,如果Message中的二进制数据块比较小的化,采用Mtom反而得不偿失。)
    (6)不管是何种编码方式,一律采用transferMode="StreamedResponse"的设置,这样可有效减低多并发所可能造成的服务器压力。

    4.今天有一个特性没有试成功,就是如何让一个实现了多个Contract的Service暴露出多个EndPoint的问题。这里就不详细记录试验的过程了,但要留个注脚,自己回头有时间了的话再看。

  • 相关阅读:
    centOS7虚拟机上搭建kvm虚拟平台
    wxpython绘制折线图
    使用Mongodb爬取中国大学排名并写入数据库
    第一个爬虫与测试
    排球比赛规则的程序化
    文件的学习
    科学计算与可视化
    面对对象的学习
    对matplotlib库的运用
    PIL成就你的自信之路
  • 原文地址:https://www.cnblogs.com/xingyukun/p/994095.html
Copyright © 2011-2022 走看看