BufferedImage始终从ByteArrayInputStream变为null

时间:2017-05-22 11:47:48

标签: java swing sockets udp jpanel

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

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

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

但BufferedImage始终为空。

客户代码:

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();
    }
}

请帮帮我。 谢谢

1 个答案:

答案 0 :(得分:0)

您的代码中存在很多错误,但是您在服务器端没有收到数据的主要原因是您不记得接收循环中的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();
}