1

我试图通过套接字将图像作为字节数组发送到客户端,以便它可以查看图像,并且一切顺利,除了查看图像碎片时,我可以查看图像的前 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;
        }
    }
}
4

3 回答 3

3

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

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

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

于 2012-07-26T18:31:49.837 回答
0

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

不知何故,您必须找到一种方法来缓冲输出,以便在溢出写入缓冲区之前刷新它。

于 2012-07-24T20:08:12.587 回答
0

Nikolai Fetissov 的回答帮助我解决了这个问题。这是我如何让它工作的:

  1. 将包含预期消息大小和消息类型的 JSON(或任何其他格式)从发送方发送到接收方。确保这是简短而甜蜜的。
  2. 立即发送您的数据。它可以是图像/音频/视频或任何东西。

奖励:这也适用于 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();
    }
}

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

于 2017-04-28T08:35:45.430 回答