7

これは、良い解決策が見つからないまま、私のアプリケーションでは数か月間深刻な問題でした。私の構成を考慮せずに、C#がStreamクラスがWCFでストリーミングする方法を管理していることに気付きました。

まず、FileStream から継承するクラスがあるため、クライアント側からいつでもどれだけ読み取られたかを監視できます。

public class FileStreamWatching : FileStream
    {
        /// <summary>        
        /// how much was read until now        
        /// </summary>        
        public long _ReadUntilNow { get; private set; }
        public FileStreamWatching(string Path, FileMode FileMode, FileAccess FileAccess)
            : base(Path, FileMode, FileAccess)
        {
            this._ReadUntilNow = 0;
        }
        public override int Read(byte[] array, int offset, int count)
        {
            int ReturnV = base.Read(array, offset, count);
            //int ReturnV = base.Read(array, offset, count);
            if (ReturnV > 0)
            {
                _ReadUntilNow += ReturnV;
                Console.WriteLine("Arr Lenght: " + array.Length);
                Console.WriteLine("Read: " + ReturnV);
                Console.WriteLine("****************************");
            }
            return ReturnV;
        }
    }

次に、ファイルを含むクライアントのストリームを読み取るサービス メソッドを以下に示します。私の主な問題は、以下のこのメソッドから呼び出すたびに FileStreamWatching.Read が開始されず、代わりに FileStreamWatching.Read が X 回呼び出すたびに 1 回開始されることです.奇妙な.

アウトプットは後で見てください

    public void Get_File_From_Client(Stream MyStream)
    {
        using (FileStream fs = new FileStream(@"C:\Upload\" + "Chat.rar", FileMode.Create))
        {
            byte[] buffer = new byte[1000];
            int bytes = 0;
            while ((bytes = MyStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                fs.Write(buffer, 0, bytes);
                fs.Flush();
            }
        }
    }

これは、FileStreamWatching.Read がアクティブ化されるたびにクライアント側で出力されます:(バッファの長さが 1000 しかないことに注意してください!)

到着時間: 256、読み取り: 256


到着時間: 4096、読み取り: 4096


到着時間: 65536、読み取り: 65536


到着時間: 65536、読み取り: 65536


到着時間: 65536、読み取り: 65536


到着時間: 65536、読み取り: 65536


....ファイル転送が完了するまで。

問題:

  1. read メソッドに持ってきたバッファの長さは 256/4096/65536 ではありません。1000です。
  2. FileStreamWatching クラスからの読み取りは、サービスから呼び出すたびに開始されません。

私の目標:

  1. 読み取りごとにクライアントからどれだけ反応するかを制御します。

  2. FileStreamWatching.Read は、サービスから呼び出すたびに開始されます。

私のクライアント構成:

<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IJob" transferMode="Streamed"/>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8080/Request2" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_IJob" contract="ServiceReference1.IJob"
                name="BasicHttpBinding_IJob" />
        </client>
    </system.serviceModel>
</configuration>

私のサービス構成(ここには構成ファイルはありません):

        BasicHttpBinding BasicHttpBinding1 = new BasicHttpBinding();
        BasicHttpBinding1.TransferMode = TransferMode.Streamed;
        //
        BasicHttpBinding1.MaxReceivedMessageSize = int.MaxValue;
        BasicHttpBinding1.ReaderQuotas.MaxArrayLength = 1000;
        BasicHttpBinding1.ReaderQuotas.MaxBytesPerRead = 1000;
        BasicHttpBinding1.MaxBufferSize = 1000;
        //
        ServiceHost host = new ServiceHost(typeof(JobImplement), new Uri("http://localhost:8080"));
        //
        ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
        behavior.HttpGetEnabled = true;
        //
        host.Description.Behaviors.Add(behavior);
        ServiceThrottlingBehavior throttle = new ServiceThrottlingBehavior();
        throttle.MaxConcurrentCalls = 1;
        host.Description.Behaviors.Add(throttle);
        //
        //
        host.AddServiceEndpoint(typeof(IJob), BasicHttpBinding1, "Request2");
        host.Open();
4

1 に答える 1

2

re: なぜ 256/4K/65535 なのですか?

ここで 2 つの可能性が考えられます。

  • ベースFileStreamは独自の内部バッファリングを行っています。read(array,offset,length)内部バッファーを埋めるために内部的に呼び出し、要求した部分を返している可能性があります。ファイル全体を読み取るまで、内部呼び出しは再帰的になります。その後、オーバーライドは何も表示しなくなります。
  • stream.read()上書きされているものとして表示されない他の署名があります。いずれかのコード パスが他のメソッドのいずれかを呼び出すreadことになる場合、カウントはオフになります。

re: MyStream が毎回最初からやり直さない

議論はMyStreamこれまでに処分されていますか?それとも新しいストリームに再利用されますか? コードはコンストラクターでのみ「再起動」するため、受信ストリームを変更するときは、オブジェクトが破棄され、再構築されていることを確認してください。

EOF に達したときに何かを表示することによって、再帰的な EOF ケースをテストすることもできます。

アプリケーション呼び出しMyStream.Readとメソッドの入口/出口の両方をカウントする静的変数を追加すると、予期しない再帰をテストできます。それらが一致しない場合FileStreamは、内部 (誤って再帰的) 呼び出しを行っています。

-ジェシー

于 2012-06-17T16:20:23.557 に答える