none
NetworkStreamとBitmap RRS feed

  • 質問

  • いつもお世話になっています。

    今回は、NetworkStreamからBitmapのデータうまくとりだせないのです。ソースコードで説明さしてもらうと

    ーーーーーークライアントーーーーーーーー

                    Rectangle rec;

                    rec = Screen.PrimaryScreen.Bounds;

                    Bitmap bmp = new Bitmap(rec.Width,rec.Height);
                    MemoryStream ms = new MemoryStream();
                    TcpClient c = new TcpClient(ipAddr, 8888);
                    NetworkStream netstream = c.GetStream();
                  

                    while (true)
                    {
                        using (Graphics g = Graphics.FromImage(bmp))
                        {
                            g.CopyFromScreen(rec.X, rec.Y, 0, 0, rec.Size, CopyPixelOperation.SourceCopy);
                        }

                        bmp.Save(ms, ImageFormat.Jpeg);
                        ms.WriteTo(netstream);
                        netstream.Flush();               

                        Thread.Sleep(100);
                    }

    --------------------------------------------------------------------------------------------------

    ---------------------------------サーバー----------------------------------------
                IPEndPoint localEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"),8888);
                TcpListener listener = new TcpListener(localEP);
                listener.Start(10);

                TcpClient client = listener.AcceptTcpClient();

                if (client.Connected)
                {
                    NetworkStream netStram;            

                    while (true)
                    {
                        netStram = client.GetStream();

                        try
                        {
                            Bitmap bitmap = new Bitmap(netStram);//ここで止まる   
                        }
                        catch
                        {
                        }
                    }
                }
    -----------------------------------------------------------------------------

    このソースのサーバー側にある「Bitmap bitmap = new Bitmap(netStram);」の行で動作がとまり、例外(System.OutOfMemoryException)がスローされます。
    ただ、クライアント側のwhile文の中にc.close()やnetstream.close()を記述すると、うまく動作します。が自分としてはストリームはつないだまま、データを送りたいのです。

    よければ御回答ください。あと、自分は学生ですので少し初心者向けの回答にしていただけると助かります。

    2009年3月18日 7:08

回答

  • Bitmap(Stream) は、与えられたストリームの最後まで読み取れることが必要です。クライアントが Close しない間は NetworkStream が終わらないので、Bitmap(Stream) に開きっぱなしの NetworkStream を与えるのは不可能です。
    必要なサイズだけ NetworkStream から新しく作った MemoryStream にコピーし、その MemoryStream を使って Bitmap(Stream) を呼び出すようにすればいいでしょう。
    そうすると今度は「必要なサイズ」をどうにかして事前に教える必要が出てきますが、まあ本体の前に付ければいいでしょう(いわゆるヘッダって奴です)。
    更にどうやって必要なサイズを取得するかという話になって、結局クライアント側も直接 NetworkStream に対して Bitmap.Save するのではなく、一旦 MemoryStream に Save して、ってことになるでしょう。
    • 回答としてマーク SE_lain 2009年3月26日 6:47
    2009年3月18日 8:15

すべての返信

  • Bitmap(Stream) は、与えられたストリームの最後まで読み取れることが必要です。クライアントが Close しない間は NetworkStream が終わらないので、Bitmap(Stream) に開きっぱなしの NetworkStream を与えるのは不可能です。
    必要なサイズだけ NetworkStream から新しく作った MemoryStream にコピーし、その MemoryStream を使って Bitmap(Stream) を呼び出すようにすればいいでしょう。
    そうすると今度は「必要なサイズ」をどうにかして事前に教える必要が出てきますが、まあ本体の前に付ければいいでしょう(いわゆるヘッダって奴です)。
    更にどうやって必要なサイズを取得するかという話になって、結局クライアント側も直接 NetworkStream に対して Bitmap.Save するのではなく、一旦 MemoryStream に Save して、ってことになるでしょう。
    • 回答としてマーク SE_lain 2009年3月26日 6:47
    2009年3月18日 8:15
  • <<Hongliangさん

    丁寧なお返事ありがとうございます。

    <<Bitmap(Stream) は、与えられた・・・
    なるほど、ストリームを最後まで読みとらないとだめだったんですね。

    <<Bitmap(Stream) は、与えられた・・・・
    おかげさまでアルゴリズムは理解できたのですが、NetworkStreamからMemoryStreamにコピーする方法がわかりません。
    御手数をかけますが、よければ教えていただけないでしょうか?
    2009年3月18日 9:08
  • 単に Read して Write するだけですよ。
    2009年3月18日 9:47
  • JPEGファイルサイズを持つbyte配列を用意して
    NetworkStream.Readメソッドで読み込み
    MemoryStreamコンストラクタに渡せばいいかと。
    2009年3月18日 13:29
  • 正確に言うと、Bitmap(Stream) は、シークができるストリームであることを前提としています。なので、最後まで読み込むことができるような Stream でも、シークができない場合はエラーが発生します。(JPEGの場合)
    ほかの画像フォーマットの場合は、大丈夫な場合もあります。

    2009年3月21日 16:58
  • Kazuya Ujihara の発言:

    正確に言うと、Bitmap(Stream) は、シークができるストリームであることを前提としています。なので、最後まで読み込むことができるような Stream でも、シークができない場合はエラーが発生します。(JPEGの場合)
    ほかの画像フォーマットの場合は、大丈夫な場合もあります。


    そんなことないはずですけど。CanSeek が false を返すようなストリームの場合、内部で一旦 EOF までメモリに読み込んでそちらを使用する実装になってますから。
    CanSeek が true を返すのに実際にシークしてみたら例外とか言うパターンならともかく。
    2009年3月21日 22:35
  • Kazuya Ujihara の発言:

    正確に言うと、Bitmap(Stream) は、シークができるストリームであることを前提としています。なので、最後まで読み込むことができるような Stream でも、シークができない場合はエラーが発生します。(JPEGの場合)
    ほかの画像フォーマットの場合は、大丈夫な場合もあります。

    追試しました。
    CanSeekでfalseを返し、Seekを実装しないStream派生クラスで実験したところ、JPEG、PNGあたりは特に問題なく動作しました。(VS2008SP1)
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    2009年3月21日 23:53
    モデレータ
  • >>佐祐理

    返事が遅くなってすいません。補足ありがとうございます。
    なるほどbyte配列に一度渡してから、書き込むんですね。
    おかげ様で解決しました。ありがとうございます。
    2009年3月26日 6:45