Java BuffereImage始终从ByteArrayInputStream为空

Java BuffereImage始终从ByteArrayInputStream为空,java,swing,sockets,udp,jpanel,Java,Swing,Sockets,Udp,Jpanel,我正在开发一个应用程序,它通过UDP套接字将客户端的屏幕截图发送到服务器 由于可以通过UDP套接字传输的最大大小为64KB,因此在传输之前我将拆分字节数组。施维雅将合并这些字节数组,得到完整的字节数组 现在我将字节数组转换为ByteArrayInputStream,然后再转换为BuffereImage 最后在JPanel中显示它 但是BuffereImage总是空的 客户端代码: import javax.imageio.ImageIO; import java.awt.*; import ja

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

由于可以通过UDP套接字传输的最大大小为64KB,因此在传输之前我将拆分字节数组。施维雅将合并这些字节数组,得到完整的字节数组

现在我将字节数组转换为ByteArrayInputStream,然后再转换为BuffereImage 最后在JPanel中显示它

但是BuffereImage总是空的

客户端代码:

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;
    }
}
导入javax.imageio.imageio;
导入java.awt.*;
导入java.awt.image.buffereImage;
导入java.io.*;
导入java.net。*;
导入java.util.array;
类UDPClient
{
公共静态void main(字符串[]args)引发异常{
DatagramSocket ds=新DatagramSocket();
InetAddress ip=InetAddress.getByName(“127.0.0.1”);
数据包dp;
while(true)
{
BuffereImage img=new Robot().createScreenCapture(新矩形(Toolkit.getDefaultToolkit().getScreenSize());
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
ImageIO.write(img,“jpeg”,baos);
paos.flush();
字节[]缓冲区=baos.toByteArray();
系统输出打印项次(缓冲区);
字节[][]dest=splitBytes(buffer,buffer.length/10);
int len=0;
if(缓冲区长度%10==0)
len=10;
其他的
len=11;
字节[]临时=新字节[]{(字节)len};
dp=新数据包(温度,温度长度,ip,3000);
ds.send(dp);
for(字节[]字节:dest)
{
dp=新数据包(字节,bytes.length,ip,3000);
ds.send(dp);
}
}
}
公共静态字节[][]拆分字节(最终字节[]数据,最终整型chunkSize)
{
最终整数长度=data.length;
最终字节[][]dest=新字节[(长度+chunkSize-1)/chunkSize]];
int destIndex=0;
int stopIndex=0;

对于(int-startIndex=0;startIndex+chunkSize,代码中有很多错误,但是您没有在服务器端接收数据的主要原因是因为您没有调用接收循环中的
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();
}
//UDP客户端
DatagramSocket ds=新DatagramSocket();
InetAddress ip=InetAddress.getByName(“127.0.0.1”);
数据包dp;
while(true)
{
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
BuffereImage img=new Robot().createScreenCapture(新矩形(Toolkit.getDefaultToolkit().getScreenSize());
ImageIO.write(img,“jpeg”,baos);
paos.flush();
字节[]缓冲区=baos.toByteArray();
//第一个更改:应该使用所需的缓冲区大小,例如1024,而不是BUFFER.length
字节[][]dest=splitBytes(缓冲区,1024);
int len=0;
if(缓冲区长度%10==0)
len=10;
其他的
len=11;
//第二个更改:您应该发送缓冲区长度,以便服务器知道要接收什么
字节[]临时=新字节[]{
(字节)(缓冲区长度和0xff),
(字节)(缓冲区长度>>8和0xff),
(字节)(缓冲区长度>>16和0xff),
(字节)(缓冲区长度>>24和0xff)
};
dp=新数据包(温度,温度长度,ip,3000);
ds.send(dp);
System.out.println(“将“+buffer.length+”字节发送到“+dest.length+”缓冲区中的服务器”);
for(字节[]字节:dest)
{
dp=新数据包(字节,bytes.length,ip,3000);
ds.send(dp);
//小心不要使UDP写入缓冲区溢出
睡眠(1);
}
}
//UDP服务器
DatagramSocket ds=null;
试一试{
ds=新的DatagramSocket(3000);
}捕获(SocketException e){
e、 printStackTrace();
}
字节[]buf=新字节[1024];
数据包dp;
JFrame=newjframe(“你好”);
维度dim=Toolkit.getDefaultToolkit().getScreenSize();
frame.setSize((int)dim.getWidth(),(int)dim.getHeight());
frame.setContentPane(这个);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
while(true)
{
//接收图像数据长度
dp=新数据包(buf,1024);
试一试{
ds.接收(dp);
}捕获(IOE异常){
e、 printStackTrace();
}
//更改:从第一个数据包读取数据长度
ByteArrayInputStream bais=新的ByteArrayInputStream(dp.getData());

int len=bais.read()+(bais.read()您的代码中有很多错误,但是您没有在服务器端接收数据的主要原因是因为您没有调用接收循环中的
ds.receive(dp)
方法

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

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

客户端和服务器之间的通信也不干净。首先,您必须将数据发送到服务器
// 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();
}