Java 通过套接字发送屏幕截图

标签 java sockets screenshot serversocket

我正在开发一个恶作剧程序,但无论如何还是有点用的。

我目前正在尝试做的是从客户端获取屏幕截图并在服务器上将屏幕截图作为 JFrame 打开。

经过多次尝试,我发现了这个悬而未决的问题How to send images through sockets in java? .

屏幕截图通过了,但它被切碎了,只有大约 120-135kb 可以通过。在投票最多的答案中,他在关闭连接之前在客户端有 Thread.sleep() 但我在没有它的情况下尝试了它并且它被切碎了所以我按照他说的那样尝试了但它仍然切碎回来。我的读取输入数据的客户端类处于循环状态,每 100 毫秒运行一次,所以我认为它循环得太快了,所以我将它增加到 1000 毫秒,但它仍然被切碎。

我在同一个线程上尝试了一些不同的答案,并在服务器端将 ImageIO.read(new ByteArrayInputStream(imageAr)) 更改为 ImageIO.read(new ByteArrayInputStream(imageAr) )) 但那次没有图像进来。

这是我开始时尝试过的原始方法之一,但根本不起作用! https://javabelazy.blogspot.com/2013/10/sending-screenshot-from-client-to.html .

服务器

package UI;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class ViewScreen implements Runnable{
private static Thread t;
@Override
public void run(){
    //Screenshot Frame
    final JFrame frame = new JFrame();
    frame.setSize(500, 500);
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    t = new Thread(){
        public void run(){
            try{
                int port = 6667;
                ServerSocket serverSocket = new ServerSocket(port);
                Socket server = serverSocket.accept();
                TrojanUI.console.append("[*]Waiting for screenshot on port " + serverSocket.getLocalPort() + "...\n");
                DataInputStream in = new DataInputStream(server.getInputStream());
                DataOutputStream out = new DataOutputStream(server.getOutputStream());
                byte[] sizeAr = new byte[4];
                in.read(sizeAr);
                int size = ByteBuffer.wrap(sizeAr).asIntBuffer().get();

                byte[] imageAr = new byte[size];
                in.read(imageAr);

                BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageAr));
                ImageIO.write(image, "jpg", new File("screen.jpg"));
                server.close();
                JLabel label = new JLabel();
                label.setIcon(new ImageIcon(image));
                frame.getContentPane().add(label);
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    };
    t.start();
    frame.setVisible(true);
}
}

这部分服务器代码是一个新的线程,创建了一个新的socket和一个新的JFrame来显示截图。我为什么要这样做?在另一个线程上,我读到只有在套接字关闭时才会发送图像。因此,由于我不希望主套接字关闭,否则我会失去连接,因此我创建了另一个套接字,该套接字将暂时打开以流式传输屏幕截图。

客户端

package tc;

import java.awt.AWTException;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;

public class SendScreen{
public SendScreen(){
    try{
        //creates new socket on port 6667
        Socket sclient = new Socket("192.168.0.5",6667);
        OutputStream sOutToServer = sclient.getOutputStream();
        DataOutputStream out = new DataOutputStream(sOutToServer);
        InputStream sInFromServer = sclient.getInputStream();
        DataInputStream in = new DataInputStream(sInFromServer);

        //Takes screenshot and sends it to server as byte array
        BufferedImage screencap = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(screencap,"jpg",baos);

        //Gets screenshot byte size and sends it to server and flushes then closes the connection
        byte[] size = ByteBuffer.allocate(4).putInt(baos.size()).array();
        out.write(size);
        out.write(baos.toByteArray());
        out.flush();
        sclient.close();
    }catch(HeadlessException | AWTException | IOException e){
        e.printStackTrace();
    }
}
}

在服务器端,我添加了另一行在本地创建图像,以便在出现任何问题时进行故障排除。

提前致谢

最佳答案

您假设 read() 填充缓冲区。规范中没有任何内容是这样说的。试试这个:

int size = in.readInt();
byte[] imageAr = new byte[size];
in.readFully(imageAr);

readInt()readFully() 保证读取正确的数量,否则尝试失败。

您在发送端也给自己带来了困难。试试这个:

out.writeInt(size);
out.write(baos.toByteArray());
out.close();

请注意 close() 之前的 flush() 是多余的,但是您应该关闭套接字周围的最外层输出流,而不是套接字,以使其自动-脸红了。

事实上,当你在每张图片后关闭连接时,你可以去掉大小字和字节数组输入/输出流,直接从/到 socket 。它将节省大量内存。

关于Java 通过套接字发送屏幕截图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41251869/

相关文章:

upload - Google 开发者屏幕截图(图形 Assets )错误图像无效

java - 这个枚举是否违反了单一职责原则?

java - 通过套接字接收图像时出现问题

c - 接收数据时触发函数的套接字

c++ - 为每个打开的应用程序截屏

android - view.getDrawingCache() 在 Android API 28 中被弃用

java - Libsvm 类不在 CLASSPATH 中

java - GWT 程序有没有办法判断它是处于托管模式还是网络模式?

在 JBOSS 上使用 CXF 处理 SOAP 请求时出现 java.lang.ClassNotFoundException

c - Linux套接字c : send data when other socket close