通过java中的套接字发送屏幕截图(bufferedImage)

发布于 2024-11-28 11:28:11 字数 5217 浏览 1 评论 0原文

我正在通过套接字发送 bufferedImage,并且使用 this 帖子:

发送方

   BufferedImage image = ....;
   ImageIO.write(image, "PNG", socket.getOutputStream());

接收方

   BufferedImage image = ImageIO.read(socket.getInputStream());

它有效 - 如果并且仅当我在这行之后关闭发送方的输出流:

 ImageIO.write(image, "PNG", socket.getOutputStream());

除了关闭输出流之外,我还能做些什么吗?

另外,我还能做些什么来避免完全使用 ImageIO 吗?做任何事情似乎都需要很长时间。 另请注意,由于性能问题,应不惜一切代价避免以任何方式读取或写入硬盘。我需要尽可能快地进行此传输,(我正在试验并尝试创建一个类似于 VNC 的客户端,并将每个屏幕截图保存到硬盘会大大减慢一切速度)..

@Jon Skeet

编辑 3:

发件人:(请注意,我发送的是 JPG 图像而不是 PNG)。

                    int filesize;
                    OutputStream out = c.getClientSocket().getOutputStream();

                    ByteArrayOutputStream bScrn = new ByteArrayOutputStream();
                    ImageIO.write(screenshot, "JPG", bScrn);
                    byte[] imgByte = bScrn.toByteArray();
                    bScrn.flush();
                    bScrn.close();

                    filesize = bScrn.size();
                    out.write(new String("#FS " + filesize).getBytes()); //Send filesize
                    out.write(new String("#<IM> \n").getBytes());        //Notify start of image

                    out.write(imgByte); //Write file
                    System.out.println("Finished");                                 

接收器:(其中 input 是套接字输入流)

尝试#1:

String str = input.toString();
imageBytes = str.getBytes();

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

System.out.println("width=" + image.getWidth());

(失败:getWidth() 行出现 Nullpointer 异常) 我理解这个错误的意思是“图像损坏”,因为它无法初始化它。正确的?

尝试#2:

byte[] imageBytes = new byte[filesize];
for (int j = 0; i < filesize; i++)
{
    imageBytes[j] = (byte) input.read();
}

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

System.out.println("width=" + image.getWidth());

(失败:getWidth() 行出现空指针异常)

尝试#3:

if (filesize > 0)
{

    int writtenBytes = 0;
    int bufferSize = client.getReceiveBufferSize();

    imageBytes = new byte[filesize];     //Create a byte array as large as the image
    byte[] buffer = new byte[bufferSize];//Create buffer


    do {
        writtenBytes += input.read(buffer); //Fill up buffer
        System.out.println(writtenBytes + "/" + filesize); //Show progress

        //Copy buffer to the byte array which will contain the full image
        System.arraycopy(buffer, 0, imageBytes, writtenBytes, client.getReceiveBufferSize());
        writtenBytes+=bufferSize;

    } while ((writtenBytes + bufferSize) < filesize);

    // Read the remaining bytes
    System.arraycopy(buffer, 0, imageBytes, writtenBytes-1, filesize-writtenBytes);
    writtenBytes += filesize-writtenBytes;
    System.out.println("Finished reading! Total read: " + writtenBytes + "/" + filesize);

}

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

(失败:接收方给出:空指针异常)

尝试 4:

   int readBytes = 0;
   imageBytes = new byte[filesize];     //Create a byte array as large as the image



    while (readBytes < filesize)
    {
        readBytes += input.read(imageBytes);
    }

    InputStream in = new ByteArrayInputStream(imageBytes);
    BufferedImage image = ImageIO.read(in);
    in.close();

    System.out.println("width=" + image.getWidth());

(失败:发送者给出:java.net.SocketException:对等方重置连接:套接字写入错误)

尝试#5:

使用 Jon skeet 的代码片段,图像到达,但仅部分地。我将其保存到文件 (1.jpg) 中以查看发生了什么,它实际上发送了 80% 的图像,而文件的其余部分则填充了空格。这会导致图像部分损坏。这是我尝试过的代码:(注意captureImg()没有错误,直接保存文件就可以了)

发送方:

    Socket s = new Socket("127.0.0.1", 1290);
    OutputStream out = s.getOutputStream();

    ByteArrayOutputStream bScrn = new ByteArrayOutputStream();
    ImageIO.write(captureImg(), "JPG", bScrn);
    byte imgBytes[] = bScrn.toByteArray();
    bScrn.close();

    out.write((Integer.toString(imgBytes.length)).getBytes());
    out.write(imgBytes,0,imgBytes.length);

接收方:

    InputStream in = clientSocket.getInputStream();
    long startTime = System.currentTimeMillis();

    byte[] b = new byte[30];
    int len = in.read(b);

    int filesize = Integer.parseInt(new String(b).substring(0, len));

    if (filesize > 0)
    {
        byte[] imgBytes = readExactly(in, filesize);
        FileOutputStream f = new FileOutputStream("C:\\Users\\Dan\\Desktop\\Pic\\1.jpg");
        f.write(imgBytes);
        f.close();

        System.out.println("done");

发送方仍然给出Connection Reset by Peer:socket write错误。 单击此处查看完整尺寸的图片 问题

I am sending a bufferedImage over a socket and I am using the example found in this post:

Sender

   BufferedImage image = ....;
   ImageIO.write(image, "PNG", socket.getOutputStream());

Receiver

   BufferedImage image = ImageIO.read(socket.getInputStream());

It works - IF, and ONLY IF, I close the sender's outputStream after this line:

 ImageIO.write(image, "PNG", socket.getOutputStream());

Is there anything I can do apart from closing the outputStream?

Also, is there anything else I can do to avoid using ImageIO altogether? It seems to take ages to do anything.
Also note that reading or writing to the hard disk in anyway should be avoided at all costs due to performance issues. I need to make this transfer as fast as possible, (I'm experimenting and trying to create a client similar to VNC and saving each screenshot to the hard disk would greatly slow down everything)..

@Jon Skeet

Edit 3:

Sender: (Note that I am sending a JPG image not a PNG).

                    int filesize;
                    OutputStream out = c.getClientSocket().getOutputStream();

                    ByteArrayOutputStream bScrn = new ByteArrayOutputStream();
                    ImageIO.write(screenshot, "JPG", bScrn);
                    byte[] imgByte = bScrn.toByteArray();
                    bScrn.flush();
                    bScrn.close();

                    filesize = bScrn.size();
                    out.write(new String("#FS " + filesize).getBytes()); //Send filesize
                    out.write(new String("#<IM> \n").getBytes());        //Notify start of image

                    out.write(imgByte); //Write file
                    System.out.println("Finished");                                 

Reciever: (where input is the socket input stream)

Attempt #1:

String str = input.toString();
imageBytes = str.getBytes();

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

System.out.println("width=" + image.getWidth());

(failed: Nullpointer exception on getWidth() line)
I understand this error to mean "corrupt image" because it couldn't initialize it. correct?

Attempt #2:

byte[] imageBytes = new byte[filesize];
for (int j = 0; i < filesize; i++)
{
    imageBytes[j] = (byte) input.read();
}

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

System.out.println("width=" + image.getWidth());

(failed: Nullpointer exception on getWidth() line)

Attempt #3:

if (filesize > 0)
{

    int writtenBytes = 0;
    int bufferSize = client.getReceiveBufferSize();

    imageBytes = new byte[filesize];     //Create a byte array as large as the image
    byte[] buffer = new byte[bufferSize];//Create buffer


    do {
        writtenBytes += input.read(buffer); //Fill up buffer
        System.out.println(writtenBytes + "/" + filesize); //Show progress

        //Copy buffer to the byte array which will contain the full image
        System.arraycopy(buffer, 0, imageBytes, writtenBytes, client.getReceiveBufferSize());
        writtenBytes+=bufferSize;

    } while ((writtenBytes + bufferSize) < filesize);

    // Read the remaining bytes
    System.arraycopy(buffer, 0, imageBytes, writtenBytes-1, filesize-writtenBytes);
    writtenBytes += filesize-writtenBytes;
    System.out.println("Finished reading! Total read: " + writtenBytes + "/" + filesize);

}

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

(failed: Reciever gives: Null pointer exception)

Attempt 4:

   int readBytes = 0;
   imageBytes = new byte[filesize];     //Create a byte array as large as the image



    while (readBytes < filesize)
    {
        readBytes += input.read(imageBytes);
    }

    InputStream in = new ByteArrayInputStream(imageBytes);
    BufferedImage image = ImageIO.read(in);
    in.close();

    System.out.println("width=" + image.getWidth());

(failed: sender gives: java.net.SocketException: Connection reset by peer: socket write error)

Attempt #5:

Using Jon skeet's code snippet, the image arrives, but only partially. I saved it to a file (1.jpg) to see what was going on, and it actually sends 80% of the image, while the rest of the file is filled with blank spaces. This results in a partially corrupt image. Here is the code I tried: (note that captureImg() is not at fault, saving the file directly works)

Sender:

    Socket s = new Socket("127.0.0.1", 1290);
    OutputStream out = s.getOutputStream();

    ByteArrayOutputStream bScrn = new ByteArrayOutputStream();
    ImageIO.write(captureImg(), "JPG", bScrn);
    byte imgBytes[] = bScrn.toByteArray();
    bScrn.close();

    out.write((Integer.toString(imgBytes.length)).getBytes());
    out.write(imgBytes,0,imgBytes.length);

Reciever:

    InputStream in = clientSocket.getInputStream();
    long startTime = System.currentTimeMillis();

    byte[] b = new byte[30];
    int len = in.read(b);

    int filesize = Integer.parseInt(new String(b).substring(0, len));

    if (filesize > 0)
    {
        byte[] imgBytes = readExactly(in, filesize);
        FileOutputStream f = new FileOutputStream("C:\\Users\\Dan\\Desktop\\Pic\\1.jpg");
        f.write(imgBytes);
        f.close();

        System.out.println("done");

The sender still gives a Connection reset by peer: socket write error.
Click here for full sized image Problem

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

秋意浓 2024-12-05 11:28:11

一种选择是将图像写入 ByteArrayOutputStream ,以便您可以确定长度,然后首先将该长度写入输出流。

然后在接收端,您可以读取长度,然后将那么多字节读入字节数组,然后创建一个 ByteArrayInputStream 来包装该数组并将传递给 ImageIO.read()

我并不完全惊讶它在输出套接字正常关闭之前不起作用 - 毕竟,包含有效 PNG 文件然后是其他内容的文件实际上不是有效的 PNG 文件就其本身而言,是吗?因此,读取器需要先读取到流的末尾,然后才能完成 - 并且网络流的“结束”仅在连接关闭时出现。

编辑:这是一种将给定数量的字节读入新字节数组的方法。作为单独的“实用”方法很方便。

public static byte[] readExactly(InputStream input, int size) throws IOException
{
    byte[] data = new byte[size];
    int index = 0;
    while (index < size)
    {
        int bytesRead = input.read(data, index, size - index);
        if (bytesRead < 0)
        {
            throw new IOException("Insufficient data in stream");
        }
        index += bytesRead;
    }
    return data;
}

One option would be to write the image to a ByteArrayOutputStream so you can determine the length, then write that length to the output stream first.

Then on the receiving end, you can read the length, then read that many bytes into a byte array, then create a ByteArrayInputStream to wrap the array and pass that to ImageIO.read().

I'm not entirely surprised that it doesn't work until the output socket is closed normally - after all, a file which contains a valid PNG file and then something else isn't actually a valid PNG file in itself, is it? So the reader needs to read to the end of the stream before it can complete - and the "end" of a network stream only comes when the connection is closed.

EDIT: Here's a method to read the given number of bytes into a new byte array. It's handy to have as a separate "utility" method.

public static byte[] readExactly(InputStream input, int size) throws IOException
{
    byte[] data = new byte[size];
    int index = 0;
    while (index < size)
    {
        int bytesRead = input.read(data, index, size - index);
        if (bytesRead < 0)
        {
            throw new IOException("Insufficient data in stream");
        }
        index += bytesRead;
    }
    return data;
}
倾听心声的旋律 2024-12-05 11:28:11

对于像我这样的其他 StackOverflow 用户。

在“乔恩·斯基特”的回答中。修改 readExactly 方法的以下行。

    <<original Line>>
    index += size;
    <<modified Line>>
    index += bytesRead;

获取完整的图像数据。

for other StackOverflow users like me.

In "Jon Skeet's" answer. Modify the following line of readExactly method.

    <<original Line>>
    index += size;
    <<modified Line>>
    index += bytesRead;

To get the full image data.

纵情客 2024-12-05 11:28:11
public static void main(String[] args) {
    Socket socket = null;
    try {
        DataInputStream dis;
        socket = new Socket("192.168.1.48",8000);
        while (true) {
            dis = new DataInputStream(socket.getInputStream());
            int len = dis.readInt();
            byte[] buffer = new byte[len];
            dis.readFully(buffer, 0, len);
            BufferedImage im = ImageIO.read(new ByteArrayInputStream(buffer));
            jlb.setIcon(new ImageIcon(im));
            jfr.add(jlb);
            jfr.pack();
            jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            jfr.setVisible(true);
            System.gc();
        }
    } catch (Exception e) {
        e.printStackTrace();
    } 
    finally {
        try {
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在 192.168.1.48:8000 机器 python 服务器运行,我得到了 java 代码中的流

public static void main(String[] args) {
    Socket socket = null;
    try {
        DataInputStream dis;
        socket = new Socket("192.168.1.48",8000);
        while (true) {
            dis = new DataInputStream(socket.getInputStream());
            int len = dis.readInt();
            byte[] buffer = new byte[len];
            dis.readFully(buffer, 0, len);
            BufferedImage im = ImageIO.read(new ByteArrayInputStream(buffer));
            jlb.setIcon(new ImageIcon(im));
            jfr.add(jlb);
            jfr.pack();
            jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            jfr.setVisible(true);
            System.gc();
        }
    } catch (Exception e) {
        e.printStackTrace();
    } 
    finally {
        try {
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

In 192.168.1.48:8000 machine python server running and i got stream in java code

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文