0

TCP サーバーからスクリーンショットをキャプチャするプログラムを作成しています。動作しますが、1 つのスクリーンショットの後、次のエラーが表示されますjava.lang.IllegalArgumentException: image == null!

また、これは私の最初の tcp プロジェクトであるため、どうすれば tcp クライアントとサーバーのコードをより堅牢にすることができるのでしょうか。コードがかなり悪いことはわかっています。これが私のコードです:

クライアント

package me.sanchixx.sss.client;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.Color;
import java.io.File;
import java.net.Socket;

import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;

@SuppressWarnings("serial")
public class Interface extends JFrame implements ActionListener
{
    JPanel container = new JPanel(new BorderLayout());
    private final JMenuBar menuBar = new JMenuBar();
    private final JMenuBar menu = new JMenuBar();
    private final JMenu mnMenu = new JMenu("Menu");
    private final JMenuItem connect = new JMenuItem("Connect");
    private final JMenuItem screenshot = new JMenuItem("Screenshot");
    private final JMenuItem save = new JMenuItem("Save");
    ImageInPanel imgPan = new ImageInPanel();
    Socket skt = null;
    String ip;
    int port;
    static BufferedImage img = null;

    public Interface()
    {
        this.setSize(600, 600);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
        this.setTitle("Stupid Spying Shit");
        this.setResizable(true);
        this.setContentPane(container);
        this.setVisible(true);
        initComponents();
    }

    void initComponents()
    {
        setJMenuBar(menuBar);
        menuBar.add(mnMenu);
        connect.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK + ActionEvent.ALT_MASK));
        mnMenu.add(connect);
        screenshot.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
        mnMenu.add(screenshot);
        mnMenu.addSeparator();
        save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
        mnMenu.add(save);
        menuBar.add(menu);
        imgPan.setBackground(new Color(0xffffff));
        container.add(imgPan);
        connect.addActionListener(this);
        screenshot.addActionListener(this);
    }

    public void actionPerformed(ActionEvent arg0) 
    {       
        if(arg0.getSource() == connect)
        {
            String adressGiven = JOptionPane.showInputDialog(null, "Server adress", "Prompt", JOptionPane.QUESTION_MESSAGE);
            if(adressGiven != null && adressGiven.length() != 0 && adressGiven.contains(":"))
            {
                String[] adress = adressGiven.split(":");
                ip = adress[0];
                port = Integer.parseInt(adress[1]);

                try 
                {
                    skt = new Socket(ip, port);
                }

                catch(Exception e) 
                {
                    JOptionPane.showMessageDialog(container, "Could not connect!", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }

            else
            {
                JOptionPane.showMessageDialog(container, "Are you serious?", "Error", JOptionPane.ERROR_MESSAGE);
            }
        }

        else if(arg0.getSource() == screenshot)
        {
            if (skt != null)
            {
                try 
                {
                    BufferedImage image = ImageIO.read(ImageIO.createImageInputStream(skt.getInputStream())); 
                    img = image;
                    System.out.print("Received image");
                    File outputfile = new File("c:/saved.png");
                    ImageIO.write(img, "jpg", outputfile);
                    repaint();
                }

                catch(Exception e) 
                {
                    e.printStackTrace();
                    JOptionPane.showMessageDialog(container, ":( " + e, "Error", JOptionPane.ERROR_MESSAGE);
                }
            }

            else
            {
                JOptionPane.showMessageDialog(container, "You are not connected to a server!", "Error", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
}

サーバ

package me.sanchixx.sss.server;

import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.net.ServerSocket;
import java.net.Socket;

import javax.imageio.ImageIO;

public class Main 
{
    public static void main(String args[]) throws Exception
    {
        @SuppressWarnings("resource")
        ServerSocket welcomeSocket = new ServerSocket(6789);

        while(true)
        {
            Socket skt = welcomeSocket.accept();
            System.out.print("Server has connected!");
            Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
            BufferedImage capture = new Robot().createScreenCapture(screenRect);
            ImageIO.write(capture, "jpg", skt.getOutputStream());
            /*try 
            {
                Thread.sleep(1000);
            } 

            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }*/
        }
    }
}

ありがとう

4

1 に答える 1

2

通常、サーバーは着信接続を受け入れ、その新しいソケット接続を処理するために新しいスレッドを生成します。

そのスレッドは、クライアントが切断されるまでループ (読み取り/書き込み) を続けます。

これで、ユーザーが「グラブ」ボタンをクリックするたびに、新しい接続を開き、画像をダウンロードして接続を閉じることができますが、接続の確立には時間がかかる場合があります。

そう。基本的な考え方は、ユーザーが「グラブ」ボタンをクリックすると、クライアントがサーバーにリクエストを送信してスクリーンショットを「グラブ」するというものです。サーバーはスクリーン ショットを生成し、それをクライアントに書き戻します。クライアントはスクリーンショットを読み込んで表示します...簡単です...

1 つだけ小さな問題があります。 ImageIOあなた(そして私)がそうあるべきだと思っているように振る舞うことはありません。イメージをソケットに単純に書き出して、ソケットのOutputStreamを使用して読み取ることはできませんInputStreamImageIO「ファイナライズ」できるように、ストリームを閉じる必要があるようです...または何か。

代わりに、それを a に書き込んでからByteArrayOutputStream、結果byteの配列をソケットの に書き込む必要がありましたOutputStream。逆に、byte配列を aに読み込み、ByteArrayOutputStreamそれを a にダンプして、...楽しいものByteArrayInputStreamに読み込ませる必要がありました;)ImageIO

ここに画像の説明を入力ここに画像の説明を入力

サーバ

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.NumberFormat;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.event.IIOWriteProgressListener;

public class Server {

    public static void main(String args[]) {
        try {
            ServerSocket welcomeSocket = new ServerSocket(6789);

            while (true) {
                System.out.println("Get next client...");
                Socket skt = welcomeSocket.accept();
                // Hand of the processing to the socket handler...
                new Thread(new SocketHandler(skt)).start();
            }
        } catch (IOException ex) {
        }
    }

    // Reads a request from the client
    // All requests must be terminated with a new line (\n)
    protected static String readRequest(InputStream is) throws IOException {
        StringBuilder sb = new StringBuilder(128);
        int in = -1;
        while ((in = is.read()) != '\n') {
            sb.append((char) in);
        }
        return sb.toString();
    }

    // Grabs the screen shot and writes to the supplied output stream
    // This will first write the byte size of the following byte array and
    // writes the byte array of the image.  Clients should expect a 
    // int value terminated by a new line character (\n)
    protected static void grabScreen(OutputStream os) throws AWTException, IOException {
        System.out.println("Grab screen shot");
        Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
        BufferedImage capture = new Robot().createScreenCapture(screenRect);

        System.out.println("Writing image to buffer...");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(capture, "jpg", baos);
        baos.close();
        System.out.println("Write byte size = " + baos.size());
        os.write((Integer.toString(baos.size()) + "\n").getBytes());
        System.out.println("Write byte stream");
        os.write(baos.toByteArray());
        System.out.println("Image sent");
    }

    // Handler for an individual client socket...
    public static class SocketHandler implements Runnable {

        private Socket socket;

        public SocketHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            String request = null;
            InputStream is = null;
            OutputStream os = null;
            try {
                System.out.println("Processing client requests");
                is = socket.getInputStream();
                os = socket.getOutputStream();
                do {
                    System.out.println("Waiting for next request");
                    request = readRequest(is);
                    System.out.println("Request = " + request);
                    if ("grab".equalsIgnoreCase(request)) {
                        grabScreen(os);
                    }
                } while (!"done".equalsIgnoreCase(request) && !"shutdown".equalsIgnoreCase(request));
                System.out.println("Client has closed");
            } catch (IOException | AWTException exp) {
                exp.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (Exception e) {
                }
            }
            // Special command to stop the server...
            if ("shutdown".equalsIgnoreCase(request)) {
                System.exit(0);
            }
        }
    }
}

クライアント

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.text.NumberFormat;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Client {

    public static void main(String[] args) {
        new Client();
    }

    public Client() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                final CapturePane capturePane = new CapturePane();

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(capturePane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.addWindowListener(new WindowAdapter() {
                    @Override
                    public void windowClosing(WindowEvent e) {
                        try {
                            capturePane.close();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                });
                frame.setVisible(true);
            }
        });
    }

    public class CapturePane extends JPanel {

        private Socket socket;
        private ScreenPane screenPane;
        private JButton grabButton;

        public CapturePane() {
            setLayout(new BorderLayout());
            screenPane = new ScreenPane();
            grabButton = new JButton("Grab");
            try {
                socket = new Socket("localhost", 6789);
            } catch (IOException ex) {
                grabButton.setEnabled(false);
                ex.printStackTrace();
            }
            add(screenPane);
            add(grabButton, BorderLayout.SOUTH);

            grabButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (socket != null) {
                        InputStream is = null;
                        OutputStream os = null;

                        ByteArrayOutputStream baos = null;
                        ByteArrayInputStream bais = null;

                        try {
                            is = socket.getInputStream();
                            os = socket.getOutputStream();
                            // Send the "grab" request...
                            writeRequest(os, "grab");
                            System.out.println("Reading image...");
                            // Read back the expected byte size of the image
                            String size = readResponse(is);

                            int expectedByteCount = Integer.parseInt(size);
                            System.out.println("Expecting " + expectedByteCount);
                            // Create a buffer for the image bytes...
                            baos = new ByteArrayOutputStream(expectedByteCount);
                            byte[] buffer = new byte[1024];
                            int bytesRead = 0;
                            int bytesIn = 0;
                            // Read the image from the server...
                            while (bytesRead < expectedByteCount) {
                                bytesIn = is.read(buffer);
                                bytesRead += bytesIn;
                                baos.write(buffer, 0, bytesIn);
                            }
                            System.out.println("Read " + bytesRead);
                            baos.close();
                            // Wrap the result in an InputStream
                            bais = new ByteArrayInputStream(baos.toByteArray());

                            // Read the image...
                            BufferedImage image = ImageIO.read(bais);
                            System.out.println("Got image...");
                            screenPane.setImage(image);
                            bais.close();
                        } catch (IOException exp) {
                            exp.printStackTrace();
                        } finally {
                            try {
                                bais.close();
                            } catch (Exception exp) {
                            }
                            try {
                                baos.close();
                            } catch (Exception exp) {
                            }
                        }
                    }
                }

                protected String readResponse(InputStream is) throws IOException {
                    StringBuilder sb = new StringBuilder(128);
                    int in = -1;
                    while ((in = is.read()) != '\n') {
                        sb.append((char) in);
                    }
                    return sb.toString();
                }

            });
        }

        protected void writeRequest(OutputStream os, String request) throws IOException {
            os.write((request + "\n").getBytes());
            os.flush();
        }

        public void close() throws IOException {
            try {
                try {
                    System.out.println("Write done...");
                    writeRequest(socket.getOutputStream(), "shutdown");
                } finally {
                    try {
                        System.out.println("Close outputstream");
                        socket.getOutputStream().close();
                    } finally {
                        try {
                            System.out.println("Close inputStream");
                            socket.getInputStream().close();
                        } finally {
                            System.out.println("Close socket");
                            socket.close();
                        }
                    }
                }
            } finally {
                socket = null;
            }
        }

    }

    public class ScreenPane extends JPanel {

        private JLabel background;

        public ScreenPane() {
            setLayout(new BorderLayout());
            background = new JLabel();
            add(new JScrollPane(background));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        public void setImage(BufferedImage img) {
            if (img != null) {
                ImageIcon icon = null;
                if (getWidth() > getHeight()) {
                    icon = new ImageIcon(img.getScaledInstance(getWidth(), -1, Image.SCALE_SMOOTH));
                } else {
                    icon = new ImageIcon(img.getScaledInstance(-1, getHeight(), Image.SCALE_SMOOTH));
                }
                background.setIcon(icon);
            } else {
                background.setIcon(null);
            }
            repaint();
        }

    }

}

話し合わなかった問題、問題、話題

  1. 現在の実装では、デフォルトのモニターのみがキャプチャされます。複数の画面がある場合、これはそれをキャプチャしません。ここに選択肢があります。仮想デスクトップ全体をキャプチャするか、クライアントがキャプチャする画面を指定できるようにします...
  2. イベント ディスパッチ スレッド内でサーバーに画面を要求すると、クライアントが「一時停止」します。これは、ローカルで実行している場合は問題にならないかもしれませんが、リモートで実行しようとすると大きな問題になるでしょう. より良い解決策は、バックグラウンド プロセスで画像を取得して読み込むことです。 SwingWorkerはこれに最適です。詳細については、Swing の同時実行を確認してください。
于 2013-08-29T11:35:31.160 に答える