BufferedImage 总是来自 ByteArrayInputStream 为空

BufferedImage always coming null from ByteArrayInputStream

我正在开发一个通过 UDP 套接字将客户端屏幕截图发送到服务器的应用程序。

由于UDP socket可以传输的最大大小是64KB,所以我在传输前拆分了字节数组。服务器将组合这些字节数组给出完整的字节数组。

现在我正在将字节数组转换为 ByteArrayInputStream,然后再转换为 BufferedImage 最后将其显示在 JPanel 中。

但 BufferedImage 始终为 null。

客户代码:

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.*;
import java.util.Arrays;

class UDPClient
{
    public static void main(String[] args) throws Exception {
        DatagramSocket ds = new DatagramSocket();
        InetAddress ip = InetAddress.getByName("127.0.0.1");
        DatagramPacket dp;
        while (true)
        {


            BufferedImage img = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(img, "jpeg", baos);
            baos.flush();
            byte[] buffer = baos.toByteArray();
            System.out.println(buffer);
            byte[][] dest=splitBytes(buffer, buffer.length / 10);
            int len=0;
            if (buffer.length%10==0)
                len=10;
            else
                len=11;
            byte[] temp=new byte[]{(byte) len};
            dp=new DatagramPacket(temp,temp.length,ip,3000);
            ds.send(dp);
            for (byte[] bytes:dest)
            {
                dp= new DatagramPacket(bytes,bytes.length, ip, 3000);
                ds.send(dp);

            }
        }
    }
    public static byte[][] splitBytes(final byte[] data, final int chunkSize)
    {
        final int length = data.length;
        final byte[][] dest = new byte[(length + chunkSize - 1)/chunkSize][];
        int destIndex = 0;
        int stopIndex = 0;

        for (int startIndex = 0; startIndex + chunkSize <= length; startIndex += chunkSize)
        {
            stopIndex += chunkSize;
            dest[destIndex++] = Arrays.copyOfRange(data, startIndex, stopIndex);
        }

        if (stopIndex < length)
            dest[destIndex] = Arrays.copyOfRange(data, stopIndex, length);

        return dest;
    }
}

服务器代码:

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.List;

class UDPServer extends JPanel
{
    static BufferedImage image;
    UDPServer() throws IOException {
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(3000);
        } catch (SocketException e) {
            e.printStackTrace();
        }
        byte[] buf = new byte[1024];
        DatagramPacket dp;
        JFrame frame=new JFrame("hello");
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setSize((int)dim.getWidth(),(int)dim.getHeight());
        frame.setContentPane(this);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        while (true)
        {
            dp= new DatagramPacket(buf, 1024);
            try {
                ds.receive(dp);
            } catch (IOException e) {
                e.printStackTrace();
            }


            int len=(int)dp.getData()[0];
            List<byte[]> blocks = new ArrayList<>();
            for (int i=1;i<=len;i++)
            {
                blocks.add(dp.getData());
            }
            byte[] imageData=concatenateByteArrays(blocks);
            InputStream bais=new ByteArrayInputStream(imageData);
            image=ImageIO.read(bais);
            System.out.println(image);

            this.repaint();


        }
    }
    public static void main(String[] args) throws Exception {

        new UDPServer();
        //ds.close();
    }
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.drawImage(image,0,0,null);
    }
    public static byte[] concatenateByteArrays(List<byte[]> blocks) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        for (byte[] b : blocks) {
            os.write(b, 0, b.length);
        }
        return os.toByteArray();
    }
}

请帮帮我。 谢谢

你的代码中有很多错误,但是你在服务器端没有收到数据的主要原因是你没有记得接收循环中的ds.receive(dp)方法。

你的程序也存在算法缺陷。看看我提出的解决方案(我检查了我电脑上的代码,截图传输成功)。

一个很大的错误可能是您知道 UDP 数据包大小限制并且不需要依赖于发送的图像大小来确定图像大小 (buffer.length / 10)。而是使用 1024 作为块大小。

客户端和服务器之间的通信也不干净。首先,您必须向服务器发送数据大小,然后是数据。另一方面,服务器可以读取数据长度,然后它知道应该读取多少个数据包。

我强烈建议您不要依赖 UDP,因为您可能会丢失数据包并且您的软件将无法运行。与其尝试重新实现某些控制算法,不如改用 TCP。

// The UDP Client

DatagramSocket ds = new DatagramSocket();
InetAddress ip = InetAddress.getByName("127.0.0.1");
DatagramPacket dp;
while (true)
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    BufferedImage img = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
    ImageIO.write(img, "jpeg", baos);
    baos.flush();

    byte[] buffer = baos.toByteArray();

    // FIRST CHANGE : YOU SHOULD USE THE BUFFER SIZE YOU WANT, LIKE 1024 INSTEAD OF buffer.length
    byte[][] dest=splitBytes(buffer, 1024);
    int len=0;
    if (buffer.length%10==0)
        len=10;
    else
        len=11;

    // SECOND CHANGE : YOU SHOULD SEND THE BUFFER LENGTH SO THAT THE SERVER KNOWS WHAT TO RECEIVE
    byte[] temp= new byte[] {
        (byte)(buffer.length&0xff),
        (byte)(buffer.length>>8&0xff),
        (byte)(buffer.length>>16&0xff),
        (byte)(buffer.length>>24&0xff)
    };
    dp=new DatagramPacket(temp,temp.length,ip,3000);
    ds.send(dp);

    System.out.println("sending "+buffer.length+ " bytes to server in " + dest.length+" buffers");

    for (byte[] bytes:dest)
    {
        dp= new DatagramPacket(bytes,bytes.length, ip, 3000);
        ds.send(dp);

        // be careful not to overflow the UDP write buffer
        Thread.sleep(1);
    }
}

// UDP Server

DatagramSocket ds = null;
try {
    ds = new DatagramSocket(3000);
} catch (SocketException e) {
    e.printStackTrace();
}

byte[] buf = new byte[1024];
DatagramPacket dp;

JFrame frame=new JFrame("hello");
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
frame.setSize((int)dim.getWidth(),(int)dim.getHeight());
frame.setContentPane(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);

while (true)
{
    // RECEIVE THE IMAGE DATA LENGTH
    dp= new DatagramPacket(buf, 1024);
    try {
        ds.receive(dp);
    } catch (IOException e) {
        e.printStackTrace();
    }

    // CHANGE : READ THE DATA LENGTH FROM THE FIRST PACKET
    ByteArrayInputStream bais = new ByteArrayInputStream(dp.getData());
    int len = bais.read()+(bais.read()<<8)+(bais.read()<<16)+(bais.read()<<24);

    List<byte[]> blocks = new ArrayList<>();

    // MAIN REASON YOUR CODE DID NOT WORK : YOU ARE NOT READING AGAIN FROM THE NETWORK
    int received = 0;
    int index = 0;
    while (received<len)
    {
        ds.receive(dp);
        received+=dp.getLength();

        // BE CAREFUL NOT ADDING THE WHOLE BUFFER, JUST THE DATA !
        byte[] toAdd = Arrays.copyOf(dp.getData(), dp.getLength());
        blocks.add(toAdd);
    }

    byte[] imageData=concatenateByteArrays(blocks);

    bais=new ByteArrayInputStream(imageData);
    image= ImageIO.read(bais);
    System.out.println(image);

    this.repaint();
}