在java中的套接字上发送屏幕截图(bufferedImage)

我在socket上发送bufferedImage,我正在使用这篇文章中的示例:

寄件人

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

接收器

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

它工作 – 如果,只有在这一行之后我关闭发送者的outputStream:

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

除了关闭outputStream之外我还能做些什么吗?

另外,我还能做些什么来避免使用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("# \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()行上的Nullpointerexception)我理解这个错误意味着“损坏的图像”,因为它无法初始化它。 正确?

尝试#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()行上的Nullpointerexception)

尝试#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(); 

(失败:接收者给出:空指针exception)

尝试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 diaet的代码片段,图像到达,但只是部分。 我将它保存到文件(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); 

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"); 

发送方仍然通过对等方重置连接:套接字写入错误。 点击此处查看完整尺寸的图片 问题

一种选择是将图像写入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 += size; } return data; } 

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

在“Jon Skeet的”答案中。 修改以下readExactly方法行。

  <> index += size; <> index += bytesRead; 

获取完整的图像数据。

 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代码流