套接字上的碎片图像字节数组

时间:2012-07-24 20:02:08

标签: android image sockets bytearray

我试图将图像作为字节数组通过套接字发送到客户端,以便它可以查看图像,一切顺利,除了查看图像的碎片,我可以查看图像的前10位,但其余的它是灰色和黑色像素,我无法弄清楚为什么

这是我服务器代码的一部分:

    public synchronized void nextFrame(VideoFrame frame) {
        // This method is called when a new frame is ready.
        // Don't forget to recycle it when done dealing with the frame.

        // draw the new frame onto the JLabel
            go = true;
            pic = frame.getBytes();
            go = false;
            label.getGraphics().drawImage(frame.getBufferedImage(), 0, 0, width, height, null);
            frame.recycle();

    }
}

class server extends Thread{
    int port;
    ServerSocket socket;
    Socket temps = null;
    boolean go = true;
    server(int p){
        port = p;
        start();
    }

    public void run(){      

        while(go == true){
            try {
                socket = new ServerSocket(port, 10);
                socket.setSoTimeout(10000);
                temps = socket.accept();
                new connect(temps);
                port += 1;
            } catch (IOException e) {
                if(e.getMessage().toString().equalsIgnoreCase("Accept timed out")){
                    go = false;
                }else{
                    e.printStackTrace();
                }
                break;
            }

        }
        try {
            socket.close();
            System.out.println("Closing socket server(no more connections will be created)");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class connect extends Thread{
    Socket connection;
    ObjectOutputStream out;
    int port;
    String host;
    GetInput in;
    connect(Socket s){
        try {
            connection = s;
            out = new ObjectOutputStream(connection.getOutputStream());
            host = connection.getInetAddress().getHostName();
            port = connection.getPort();
            System.out.println("Connected to " + host + ":" + port);
            in = new GetInput(connection);
            start();
        } catch (IOException e) {
            e.printStackTrace();
        }   
    }

    public void run(){
        try {
            out.writeInt(Main.pic.length);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        while(in.isAlive()){
            if(Main.go){    
                try {
                    out.write(Main.pic);
                } catch (IOException e) {
                        e.getMessage().toString();
                }
            }
        }
        try {
            out.close();
            connection.close();
            System.out.println("Closing " + host + ":" + port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
class GetInput extends Thread{
    ObjectInputStream in;
    GetInput(Socket s){
        try {
            in = new ObjectInputStream(s.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        start();
    }
    public void run(){
        try{
            boolean go = in.readBoolean();
            int a = (go?1:0);
            System.out.println(a);
        } catch (IOException e) {
                e.getMessage().toString();
        }
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

我知道帧抓取器正在抓取图像,因为我还在服务器上显示图像并且它看起来很好,这意味着字节数组没有正确地通过套接字发送,但为什么呢?

编辑:继承我的客户端代码,它是一个Android应用程序

package org.smiley.doom;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

public class ClientActivity extends Activity implements View.OnClickListener{

    Socket s;
    InetAddress inet;
    ObjectOutputStream out;
    ObjectInputStream in;
    TextView log;
    ImageView im;
    Button send;
    EditText tip;
    int rport;
    String ip;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        tip = (EditText) findViewById(R.id.etIP);
        send = (Button) findViewById(R.id.bSEND);
        im = (ImageView) findViewById(R.id.ivPIC);
        log = (TextView) findViewById(R.id.tvLog);

        s = null;
        in = null;
        out = null;

        send.setOnClickListener(this);
    }

    @Override
    public void onClick(View arg0) {
        switch(arg0.getId()){
            case R.id.bSEND:
                final int len;
                    try {
                        inet = InetAddress.getByName("192.168.0.2");
                        s = new Socket(inet, 4321);
                        in = new ObjectInputStream(s.getInputStream());
                        out = new ObjectOutputStream(s.getOutputStream());
                        log.setText("Client opened");
                        len = in.readInt();
                        new Thread(new Runnable(){

                            @Override
                            public void run() {
                                    byte[] b = new byte[len];
                                    try {
                                        in.read(b);
                                        log.setText(""+s.getReceiveBufferSize());
                                    } catch (IOException e1) {
                                        e1.printStackTrace();
                                    }
                                    final byte[] l = b;
                                    im.post(new Runnable(){
                                        @Override
                                        public void run() {
                                            Bitmap bmp = BitmapFactory.decodeByteArray(l, 0, l.length);
                                            im.setImageBitmap(bmp);                             
                                        }
                                    });
                                    try {
                                        out.writeBoolean(true);
                                        out.close();
                                        in.close();
                                        s.close();
                                        //log.setText("Client closed");
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                            }

                        }).start();;
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            break;
        }
    }
}

3 个答案:

答案 0 :(得分:3)

TCP仅向应用程序提供与当前可用字节数一样多的字节。由于底层网络层(IP)是基于数据包的,因此您的流在传输过程中会被分成多个部分。接收端的网络堆栈从网卡上获取这些块(数据包)并缓冲它们直到应用程序从给定的套接字读取,此时您获得缓冲区大小的min以及操作系统中堆积的内容套接字缓冲区。

由于TCP连接代表,操作系统对您的应用程序消息一无所知,因此您有责任将所有内容重新组合在一起。

您必须在循环中读取套接字,直到您知道自己拥有所有数据。最简单的方法是告诉客户端你要发送多少字节。

答案 1 :(得分:0)

您的数据段(图像)可能比缓冲区大得多。

不知何故,你必须找到一种缓冲输出的方法,这样你就可以在溢出写缓冲区之前将其刷新。

答案 2 :(得分:0)

Nikolai Fetissov的回答帮助我解决了这个问题。以下是我如何使用它:

  1. 发送包含预期消息的JSON(或任何其他格式) 从发件人到收件人的大小和消息类型。确保这是 简短又甜蜜。
  2. 立即发送您的数据。它可能是图像/音频/视频或任何东西。
  3. 奖励:这也适用于Android蓝牙/ Wifi套接字。

    要使用的代码段:

    byte[] fileBuffer = null;
    int bytes = 0, expectedFileSize = 0, messageType = Constants.TYPE_IMAGE;
    boolean isProcessing = false;
    while (isReading) {
        try {
            if (isProcessing) {
                // Fragment arrived
                byte[] buffer = new byte[1024];
                int currentSize = mmInStream.read(buffer);
    
                // Keep appending to the fileBuffer
                System.arraycopy(buffer, 0, fileBuffer, bytes, currentSize);
                bytes += currentSize;
                if (bytes == expectedFileSize) {
                    // Your message is ready. Send it!
                    sendIt(fileBuffer, messageType);
                    isProcessing = false;
                    bytes = 0;
                }
            } else {
                byte[] buffer = new byte[1024];
                bytes = mmInStream.read(buffer);
                try {
                    // Message is a JSON. Next set of messages will be audio or image.
                    JSONObject json = new JSONObject(new String(buffer, 0, bytes));
                    expectedFileSize = json.getInt(Constants.MESSAGE_SIZE);
                    messageType = json.getInt(Constants.MESSAGE_TYPE);
                    fileBuffer = new byte[expectedFileSize];
                    isProcessing = true;
                    bytes = 0;
                } catch (JSONException e) {
                    // This is a normal message. Send it without processing.
                    sendIt(buffer, Constants.TYPE_TEXT);
                    isProcessing = false;
                    bytes = 0;
                }
            }
        } catch (IOException e) {
          e.printStackTrace();
        }
    }
    

    欢迎对代码进行编辑以进一步优化它!希望这会有所帮助。