通过java中的套接字发送屏幕截图(bufferedImage)
我正在通过套接字发送 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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
一种选择是将图像写入 ByteArrayOutputStream ,以便您可以确定长度,然后首先将该长度写入输出流。
然后在接收端,您可以读取长度,然后将那么多字节读入字节数组,然后创建一个 ByteArrayInputStream 来包装该数组并将该传递给
ImageIO.read()
。我并不完全惊讶它在输出套接字正常关闭之前不起作用 - 毕竟,包含有效 PNG 文件然后是其他内容的文件实际上不是有效的 PNG 文件就其本身而言,是吗?因此,读取器需要先读取到流的末尾,然后才能完成 - 并且网络流的“结束”仅在连接关闭时出现。
编辑:这是一种将给定数量的字节读入新字节数组的方法。作为单独的“实用”方法很方便。
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 toImageIO.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.
对于像我这样的其他 StackOverflow 用户。
在“乔恩·斯基特”的回答中。修改 readExactly 方法的以下行。
获取完整的图像数据。
for other StackOverflow users like me.
In "Jon Skeet's" answer. Modify the following line of readExactly method.
To get the full image data.
在 192.168.1.48:8000 机器 python 服务器运行,我得到了 java 代码中的流
In 192.168.1.48:8000 machine python server running and i got stream in java code