0

画像を送信することを目的とした「サーバー」から、Android デバイスである「クライアント」に画像を送信しようとしています。その間のソケットは開いたままになり、画像が来続けます。問題は:

  1. 画像のサイズがわかりません (変更される可能性があります)。
  2. 画像は BMP 形式ではありません。

以下の私のコードでは:

  1. 画像が転送された後、クライアントは読み取りを停止しません (-1読み取られたときに取得できません)。ソケットが閉じられたときに停止します。
  2. 読み取りが終了した後、入力ストリームはクリアされず、同じイメージが何度も読み取られます。

最初に、サイズがわかっている 2 つの BMP 画像 (両方とも同じサイズ) を送信しようとしました。サーバーコードは次のとおりです。

    public static void main(String[] args) {
        try {
            ServerSocket s = new ServerSocket(4488);
            System.out.println("Waiting for a connection . . . . ");
            Socket socket = s.accept();
            System.out.println("Connected!");
            DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
            Thread.sleep(2000);

            File myImageFile = new File("c:\\1\\a.bmp");
            FileInputStream fis = new FileInputStream(myImageFile);
            byte[] data = new byte[(int) myImageFile.length()];
            byte[] tmp = new byte[0];
            byte[] myArrayImage = new byte[0];
            int len = 0 ;
            int total = 0;

            while( (len = fis.read(data)) != -1 ) {
                total += len;
                tmp = myArrayImage;
                myArrayImage = new byte[total];
                System.arraycopy(tmp,0,myArrayImage,0,tmp.length);
                System.arraycopy(data,0,myArrayImage,tmp.length,len);
            }

            //

            fis.close();

            dataOutputStream.write(myArrayImage);
            dataOutputStream.flush();
            Thread.sleep(2000);

            myImageFile = new File("c:\\1\\b.bmp");
            fis = new FileInputStream(myImageFile);
            data = new byte[(int) myImageFile.length()];
            tmp = new byte[0];
            myArrayImage = new byte[0];
            len = 0 ;
            total = 0;

            while( (len = fis.read(data)) != -1 ) {
                total += len;
                tmp = myArrayImage;
                myArrayImage = new byte[total];
                System.arraycopy(tmp,0,myArrayImage,0,tmp.length);
                System.arraycopy(data,0,myArrayImage,tmp.length,len);
            }

            fis.close();

            dataOutputStream.write(myArrayImage);
            dataOutputStream.flush();
            Thread.sleep(2000);

            socket.close();
            s.close();

クライアントコードは次のとおりです。

    @Override
public void run() {
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    byte[] byteChunk = null;
    int c;

    if (_dataInputStream != null) {
        while (true) {
            try {
                Thread.sleep(200);
            } catch (Exception e) {
            }

            try {
                byteChunk = new byte[1024];

                while ((c = _dataInputStream.read(byteChunk)) != -1){
                    buffer.write(byteChunk, 0, byteChunk.length);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }



            final Bitmap bitmap = BitmapFactory.decodeByteArray(buffer.toByteArray(), 0, buffer.size());

            if (bitmap != null) {
                _handler.post(new Runnable() {
                    public void run() {
                        _iv.setImageBitmap(bitmap);
                        _iv.invalidate();
                    }
                }); 
            }

                buffer.reset();
        }
    }
}

さて、私が言ったように、ソケットが閉じられるまでクライアントはwhileループにとどまり、その後(クライアント側で1つの画像にのみ適合するバイト配列を作成したため、送信する画像の数に関係なく)これを読み続けますいつも最初の画像。

私が間違っていることはありますか?

Ps 画像が BMP でない場合、クライアント側のコードで記述したデコードは機能しますか? 送りたい実画像はPNGです。

4

5 に答える 5

1

最初に画像バイト配列のサイズを送信し、次にwhileループで次のようなサイズに達するまでバイトを読み取ることができます:

DataInputStream in = conn.openDataInputStream();

            // read a length first
            int length = in.readInt();


            if (length <= 0) {
                throw new IOException("Can't read a length");
            }

            // read the image now
            imgData = new byte[length];
            length = 0;

            while (length != imgData.length) {
                int n = in.read(imgData, length, imgData.length - length);

                if (n == -1) {
                    throw new IOException("Can't read a image data");
                }

                length += n;
            }

            in.close();

これはこれの編集版です

画像のサイズが int で、1 バイトを超える場合は、writeint を使用する必要があることに注意してください。

于 2013-05-22T07:20:59.753 に答える
0

入力の終了を示すメカニズムを使用しない限り、クライアントがストリームからの読み取りを停止するタイミングを知る方法はありません。

簡単な修正は、次のデータの長さをクライアントに通知するストリームに書き込む固定長(4バイト、ほとんどの画像ではintで十分です)ヘッダーを使用することです。次に、クライアントはストリームからそのバイト数を読み取ってから、他のヘッダーを停止して待機するか、ストリームを閉じます。

もう1つのアプローチは、ファイル終了区切り文字を使用して、入力の終了が検出されたことをクライアントに通知することです。

入力後にストリームを閉じない限り、画像自体に加えて、ストリームにいくつかの追加データ(メタデータ)を書き込む必要があります。

于 2012-06-12T07:43:38.867 に答える
0

jpegこんにちは、ファイルを読みたい場合は、このコードを使用できます

byte[] bytes = new byte[1024 * 1024];
int count = 0;
do
{
    count += in.read(bytes, count, bytes.length - count);
}while (!(count > 4 && bytes[count - 2] == (byte) -1 && bytes[count - 1] == (byte) -39));

しかし、私はPNGフォーマットを読む方法を理解することができません

于 2012-07-02T06:24:28.200 に答える
0

クライアントコードだけを見ましたが、これはコメントに収まりません。自分がしていることを再考する必要があります。あなたの考え方(私は最初の試みで同じことをしますは、コンピューターベースではなく、人間ベースのようなものです. 言い換えれば、あなたのコードは人間であるには意味がありますが、その理由はよくわかりませんし、コンピューターにとっては意味がありません。

要点:while (true)ループには出口がありません。無限です。「ビットマップ」への最後の読み取りを繰り返し繰り返すことを期待しています。

まず、sleepコードを削除します。今は問題を混乱させています。何らかの方法で役立つ場合は、後で元に戻すことができます。(そうなるとは思いません。読み取りは必要なすべてのブロッキングを行います。)次に、完全な画像が読み取られたときに読み取りループから抜け出すために、画像の終わりマーカーまたは何かが必要です。(または、このループに配置された画像処理コードをトリガーします。)

最後に、ループから抜け出すために、ファイルの終わりまたは画像の終わりのマーカーが必要です。while (true)(「要点」に戻ります。)

于 2012-06-13T18:12:36.490 に答える
-1

PNG を送信する場合は、形式について少しお読みください ( Wiki )。各チャンクには長さがプレフィックスされているため、ネットワーク経由でそのまま送信して、いつ終了するかを知ることができます!

于 2012-06-12T08:57:44.080 に答える