1

sslストリーム(Webサイトから)からのデータを画面に表示しようとしています。データがいつ到着するかわからないので、バイトが読み取られるまでストリームから読み取りを続ける別のスレッドを使用しました。これは完全に機能しますが、CPU使用率は25%に跳ね上がり、そこにとどまります(これは、最大使用量で1スレッド、私のPCには4スレッドです)。スレッドがwhileループでスタックしているため、これは少し意味がありますが、ThreadクラスのインスタンスがCPUのスレッド全体を消費することは期待していませんでした(単純なClient/を使用している場合はこれが発生していないことを誓うことができます。サーバーアプリケーション)。

接続が初期化されるとすぐにスレッドの実行が開始され、ユーザーはいつでもWebサイトにデータを送信でき、アプリケーションは応答を出力することになっています。これに対する代替ソリューションは何でしょうか?SslStreamを削除して、他のものを使い始める必要がありますか?

この別のスレッドで実行されるコードは次のとおりです。

    void ReadDataAsync(Object obj) {
        byte[] buffer = new byte[65536]; //65536, make sure all bytes can be
                                         //from a single packet
        int bytesRead = -1;

        while (true) {
            //It makes sense for sslStream.Read to block until bytes have been
            //read, but it doesn't.  Which is why I'm checking if bytesRead!=0

            bytesRead = sslStream.Read(buffer, 0, 65536);

            if (bytesRead != 0) {
                Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, bytesRead));
                buffer = new byte[65536];
            }
        }
    }

みなさん、ありがとうございました。

編集:
「gt」が示唆するように、代わりにBeginReadとEndReadを使用してみました。このために、ユーザーからリクエストが送信されるたびにBeginReadを使用しています。すべてのデータを受信したら、画面に印刷します。これはうまくいくようですが、将来問題が発生するかどうか心配です。パケットがめちゃくちゃになる可能性はありますか?たとえば、EndReadが最初のパケットの最後に0を返さず、2番目のパケットを読み取り続ける可能性はありますか?それが可能であれば、どうすればこれを解決できますか?受信したデータはhttp層の本体にすぎないため、パケットの長さを知るために事前にIP層にアクセスすることはできません。

    public void SendData(byte[] message) {
        sslStream.Write(message);
        sslStream.Flush();

        //Start reading for response (if not already reading)
        if (sslStream.CanRead) {
            sslStream.BeginRead(buffer, 0, BufferSize, ReadData, null);
        }
    }

    void ReadData(IAsyncResult ar) {
        int bytesRead = sslStream.EndRead(ar);

        if (bytesRead > 0) {
            //data may be on their way so start reading again
            message.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
            sslStream.BeginRead(buffer, 0, BufferSize, ReadData, null);
            Console.WriteLine("Data received but more may be on their way...");
        } else {
            //All data arrived (Checking if length is more than 0 since all the
            //data may had already arrived in the previous check (above)
            if (message.ToString().Length > 0) {
                Console.WriteLine(message.ToString());
                //Clear StringBuilder and reset buffer.
                message.Clear();
                buffer = new byte[BufferSize];
            }
        }
    }

再度、感謝します

4

1 に答える 1

1

通常、表示は悪い兆候while(true)です...コードが終了条件なしで「タイトな」ループに入ると、ループを継続し、使用可能なすべてのリソースを消費します。

'if'条件が期待どおりに機能していることを再確認してください。たとえば、ストリームが複数の部分で読み取られた場合はどうなりますか?(たとえば、32768の2つの部分)。これは完全に可能です。

動作に満足したらRead、を使用して、次を試す前にスレッドを少し強制的にスリープさせることができますThread.Sleep(100)

または、を使用して非同期IOを調べてみてくださいBeginReadMSDNのこの例を参照してください。


編集して、質問のパート2に答えます。

何かがうまくいかない場合はうまくいかないのではないかと思うので、防御的にコーディングしてください!次の問題の解決策は、ストリームから読み取られたすべてのデータをバッファリングすることです。次に、別のスレッドでバッファからパケット全体を読み取ろうとします。バッファが同時に読み取り/書き込みされるのを防ぐために、ロックを使用することを忘れないでください。

また、「断片化された」動作(および通常の動作)をカバーするために、このための単体テストを作成することもお勧めします。

または、これらの処理を行う高レベルのプロトコルを調べることができる場合もあります。私がよく言及するのは、GoogleのProtocolBuffersです。

于 2013-03-25T14:57:22.920 に答える