Remote Screen Übertragung war Remote Anwendung - CORBA?

flashray

Erfahrenes Mitglied
Hallo,

ich habe meine erste Testanwendung mit CORBA geschrieben. Habe es bisher nur lokal ausprobiert. Es funktioniert soweit. Der Client macht Screenshots in bestimmten Zeitabständen und sendet diese an den Server, der diese in einem JFrame zeichnet.

Remote.idl
Code:
interface Remote
{
  typedef sequence<long> pixSeq;
  void dump(in long width, in long height, in pixSeq pixels);
};

GUIClient.java
Java:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import javax.swing.*;
import org.omg.CORBA.*;
import static java.lang.System.*;

public class GUIClient extends JPanel {
  private ORB orb; 
  private Remote r;
  
  private BufferedImage bufImg;
  private Dimension d;
  private int[] iArray;
  private Robot rob;
  
  private void initializeORB(String[] args) {
    Properties props = getProperties();
    orb = ORB.init(args, props);
  }
  private org.omg.CORBA.Object getRef(String refFile) {
    String ref = null;
    try {
      Scanner reader = new Scanner(new File(refFile));
      ref = reader.nextLine();
    } catch (IOException ex) {
      out.println("File error: "
        + ex.getMessage());
      exit(2);
    }
    org.omg.CORBA.Object obj = orb.string_to_object(ref);
    if (obj == null) {
      out.println("Invalid IOR");
      exit(4);
    }
    return obj;
  }
  
  private void createGUI() {
    final JLabel label = new JLabel("   ");
	label.setForeground(Color.RED);
    add(label);
	
	rob = null;
		try {
			rob = new Robot();
		} catch (AWTException e) {
			e.printStackTrace();
	}
	
	bufImg = null;
	d = Toolkit.getDefaultToolkit().getScreenSize();
	iArray = new int[d.width*d.height];
	
	new Thread() {
		public void run() {
			while (true){
				try {
				bufImg = rob.createScreenCapture(new Rectangle(d));
				bufImg.getRGB(0, 0, d.width, d.height, iArray,0,d.width);
				label.setText(" \u2022 ");
				r.dump(d.width,d.height,iArray);
				label.setText("   ");
				Thread.sleep(1000);
				} catch (InterruptedException e) {
				e.printStackTrace();
				}
			}			
		}
	}.start();
	
  }
  
  public GUIClient(String[] args, String refFile) {
    initializeORB(args);
    org.omg.CORBA.Object obj = getRef(refFile);
    try {
      r = RemoteHelper.narrow(obj);
    } catch (BAD_PARAM ex) {
      out.println("Narrowing failed"); 
      exit(3);
    }
    createGUI();
  }
  public static void main(String[] args) {
    try {
      String refFile = "Remote.ref";
      JDialog d = new JDialog(new JFrame(),"Qalem Remote Client");
      d.getContentPane().add(
        new GUIClient(args, refFile));
      d.pack();
	  d.setAlwaysOnTop(true);
      d.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
	  });
      d.setVisible(true);
    } catch (Exception ex) {
      out.println("Exception: " + ex.getMessage()); 
      exit(1);
    }
  }
}

DelegationServer.java
Java:
import java.io.*;
import java.util.Properties;
import org.omg.CORBA.*;
import org.omg.PortableServer.*;
import javax.swing.*;
import static java.lang.System.*;

public class DelegationServer {
  public static void main(String[] args) {
    try {
      RemoteDelegate rd;
      JFrame f = new JFrame("Qalem Remote Server 0.1");
      f.getContentPane().add(rd = new RemoteDelegate());
      f.setSize(200,200);
	  f.setLocationByPlatform(true);
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	  f.setAlwaysOnTop(true);
      f.setVisible(true);
      Properties props = getProperties();
      ORB orb = ORB.init(args, props);      
      org.omg.CORBA.Object obj = null;
      POA rootPOA = null;
      try {
        obj = orb.resolve_initial_references("RootPOA");
        rootPOA = POAHelper.narrow(obj);
      } catch (org.omg.CORBA.ORBPackage.InvalidName e) { }
      RemotePOATie r_impl = new RemotePOATie(rd);
      Remote r = r_impl._this(orb);
      try {
        FileOutputStream file = 
          new FileOutputStream("Remote.ref");
        PrintWriter writer = new PrintWriter(file);
        String ref = orb.object_to_string(r);
        writer.println(ref);
        writer.flush();
        file.close();
        out.println("Server started."
          + " Stop: Close-Button");
      } catch(IOException ex) {
        err.println("File error: " 
          + ex.getMessage());
        exit(2);
      }
      rootPOA.the_POAManager().activate();
      orb.run();
    } catch(Exception ex) {
      out.println("Exception: " + ex.getMessage());
      exit(1);
    }
  }
}

RemoteDelegate.java
Java:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class RemoteDelegate extends JPanel 
    implements RemoteOperations {
  
  private BufferedImage bufImg;

  public void dump (int width, int height, int[] pixels){
    bufImg = new BufferedImage(width, height,BufferedImage.TYPE_INT_ARGB);
	bufImg.setRGB(0, 0, width, height, pixels, 0, width);
	this.repaint();
  }
  
  public void paint (Graphics g){
    super.paint(g);
	if (bufImg != null)
	  g.drawImage(bufImg, 0, 0, this);
  }
}

Das Ziel dieser Client Server Anwendung ist, das der der den Server bei sich laufen hat, den Desktop des PCs mit dem Clienten life miterleben darf. Life heißt dann, vielleicht ein Paar Screenshots pro Sekunde.

Der Client wandelt das Screenshot welchen der Robot schießt in ein int array das zum Server gesendet und dort gezeichnet wird.

Ist das so OK, das mehrmals pro Sekunde eine remote Verbindung über das Internet aufgebaut wird. Oder gibt es da eine effizientere Variante, bei dem vielleicht, eine Verbindung aufgebaut wird, welche auch beständig bleibt, über diese eine Verbindung dann das Bild beständig gesendet werden kann?


Vg Erdal
 
Re: Remote Anwendung - CORBA?

Ich habe die Schlafzeit zwischen den Screenshots auf eine Millisekunde gesetzt. Obwohl die Anwendung lokal läuft, dauert es mindestens 3 bis 4 Sekunden das der Server aktualisiert wird und es belastet die CPU sehr.

Hätte jemand vielleicht Tips, was ich da besser gestallten kann?

Vg Erdal
 
Re: Remote Anwendung - CORBA?

Das gleiche in einer einzigen Anwendung läuft natürlich schneller. Hier wird die Anzeige ca. jede Sekunde aktualisiert. Das ist noch OK für meinen Anwendungszweck, aber 3 bis 4 Sekunden (bei voller CPU Leistung) sind nicht akzeptabel.

Die RemoteDesktopVerbindung von WinXP kann das sehr performant, also muss das doch auch irgendwie mit Javamitteln möglich sein. RMI, Sockets vielleicht? Jemand eine Idee?

Java:
import java.awt.*;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class TransferImage extends JPanel {

	private BufferedImage bufImg;

	private BufferedImage bufImg2;

	private Dimension d;

	private Robot r = null;

	private int[] iArray;

	public TransferImage() {
		try {
			r = new Robot();
		} catch (AWTException e) {
			e.printStackTrace();
		}

		d = Toolkit.getDefaultToolkit().getScreenSize();

		iArray = new int[d.width * d.height];

		bufImg2 = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);

		new Thread() {
			public void run() {
				while (true) {
					bufImg = r.createScreenCapture(new Rectangle(d));
					bufImg.getRGB(0, 0, d.width, d.height, iArray, 0, d.width);
					bufImg2.setRGB(0, 0, d.width, d.height, iArray, 0, d.width);
					TransferImage.this.repaint();

					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

	public static void main(String[] args) {
		JFrame f = new JFrame();
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setLocationByPlatform(true);
		f.setAlwaysOnTop(true);
		f.setSize(320, 480);

		f.add(new TransferImage());

		f.setVisible(true);
	}

	public void paint(Graphics g) {
		super.paint(g);
		if (bufImg2 != null)
			g.drawImage(bufImg2, 0, 0, this);
	}
}


Vg Erdal
 
Das ist interessant - daran bastle ich auch gerade, allerdings leider mit dem selben Ansatz, der sich im Betrieb als viel zu langsam herausgestellt hat...

Vielleicht wäre es möglich, direkt den Grafikkarten-Stream abzugreifen und über's Netz zu schicken? Wäre schonmal "etwas" performanter, weil sich die CPU so nicht andauernd mit den Screenshots beschäftigen muss.

Um allerdings den Netzverkehr zu entlasten, dürfte man theoretisch nur Änderungen anstatt ganzen Bildern übermitteln... Das benötigt aber einen rechnungsaufwändigen Algorithmus, der noch mehr Leistung schluckt, als der Jetzige...


Aber ich gebe die Frage bzgl. der Grafikkarte einfach mal weiter!
 
Hallo!

Das ScreenCapture über den java.awt.Robot ist super langsam und rechenintensiv, darauf lässt sich kaum eine flüssige Bildübertragung aufbauen. Ich würde einfach einen VNC Server installieren und dessen Datenstrom mit Java abgreifen... wie das geht sieht man am besten an dem Java Applet das bei den meisten VNC Servern mitgeliefert wird.
Die Bilder würde ich über ganz normale Sockets bzw. NIO SocketChannels versenden.

RMI und CORBA für die Übertragung von kontinuierlichen Bilddaten ist IMHO keine gute Idee...
Das einzige was ich da über RMI schicken würde wären eventuell ein paar MetaDaten zum Stream.

Gruß Tom
 
Hallo Tom,

habe mein lokal Beispiel etwas umgeändert. Ich übergebe jetzt nicht ein int array sondern speichere das BufferedImage einfach in ein anderes. So dauert die Aktualisierung ca. 0,7 Sekunden. Vorher waren es ca. 1,5 Sekunden.

Werd mal die Sache demnächst über Sockets versuchen. Muss mich aber erst noch einarbeiten :) .

Java:
import java.awt.*;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class TransferImage extends JPanel {

	private BufferedImage bufImg;

	private BufferedImage bufImg2;

	private Dimension d;

	private Robot r = null;

	private int[] iArray;

	private long time;
	
	public TransferImage() {
		try {
			r = new Robot();
		} catch (AWTException e) {
			e.printStackTrace();
		}

		d = Toolkit.getDefaultToolkit().getScreenSize();

		iArray = new int[d.width * d.height];

		bufImg2 = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);
		
		new Thread() {
			public void run() {
				while (true) {
					System.out.println(System.currentTimeMillis() - time);
					time = System.currentTimeMillis();
					bufImg = r.createScreenCapture(new Rectangle(d));
					
					bufImg2 = bufImg;
					
					//bufImg.getRGB(0, 0, d.width, d.height, iArray, 0, d.width);
					//bufImg2.setRGB(0, 0, d.width, d.height, iArray, 0, d.width);
					TransferImage.this.repaint();

					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

	public static void main(String[] args) {
		JFrame f = new JFrame();
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setLocationByPlatform(true);
		f.setAlwaysOnTop(true);
		f.setSize(320, 480);

		f.add(new TransferImage());

		f.setVisible(true);
	}

	public void paint(Graphics g) {
		super.paint(g);
		if (bufImg2 != null)
			g.drawImage(bufImg2, 0, 0, this);
	}
}


Vg Erdal
 
Hallo!

So kannst du ScreenShots von einem Rechner zum anderen übertragen... auf einem Rechner mit nur einem Monitor lässt sich das prima mit VMWare ausprobieren, aber das mal nur am Rande ;-)

Unser ScreenProvider (Server)
(Kann mehrere Clients "gleichzeitig" bedienen)
Java:
package de.tutorials;

import java.awt.AWTException;
import java.awt.DisplayMode;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class ScreenProvider implements Runnable {

	Robot robot;
	Rectangle screen;
	int port;
	Set<Socket> clientSockets;
	ExecutorService executorService;

	public ScreenProvider(int port) {
		try {
			this.robot = new Robot();
			DisplayMode displayMode = GraphicsEnvironment
					.getLocalGraphicsEnvironment().getDefaultScreenDevice()
					.getDisplayMode();
			this.screen = new Rectangle(0, 0, displayMode.getWidth(),
					displayMode.getHeight());
			this.port = port;
			this.clientSockets = new CopyOnWriteArraySet<Socket>();
			this.executorService = Executors.newCachedThreadPool();
		} catch (AWTException e) {
			throw new RuntimeException(e);
		}
	}

	public static void main(String[] args) {
		Executors.newSingleThreadExecutor().execute(new ScreenProvider(4711));
	}

	public void run() {
		executorService.execute(createClientConnectionAcceptor());

		while (true) {
			if (!clientSockets.isEmpty()) {
				BufferedImage image = captureScreenShot();
				ByteArrayOutputStream bout = new ByteArrayOutputStream();
				JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bout);
				try {
					encoder.encode(image);
				} catch (Exception e) {
					e.printStackTrace();
				}

				for (Socket clientSocket : clientSockets) {
					try {
						clientSocket.getOutputStream()
								.write(bout.toByteArray());
					} catch (IOException e) {
						e.printStackTrace();
						try {
							clientSocket.close();
							clientSockets.remove(clientSocket);
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					}
				}
			}
			try {
				TimeUnit.MILLISECONDS.sleep(250);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private Runnable createClientConnectionAcceptor() {
		return new Runnable() {

			public void run() {
				try {
					ServerSocket serverSocket = new ServerSocket(port);
					while (true) {
						clientSockets.add(serverSocket.accept());
					}
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		};
	}

	private BufferedImage captureScreenShot() {
		return this.robot.createScreenCapture(screen);
	}
}

Unser ScreenConsumer (Client):
Java:
package de.tutorials;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.Socket;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.swing.JFrame;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageDecoder;

public class ScreenConsumer extends JFrame implements Runnable {

	public ScreenConsumer() {
		super("ScreenFetcher");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setSize(1024, 768);
		setVisible(true);
	}

	public static void main(String[] args) {
		Executors.newSingleThreadExecutor().execute(new ScreenConsumer());
	}

	public void run() {
		try {
			Socket socket = new Socket("192.168.163.128", 4711);
			InputStream inputStream = new BufferedInputStream(socket
					.getInputStream());
			while (true) {
				try {
					JPEGImageDecoder decoder = JPEGCodec
							.createJPEGDecoder(inputStream);
					BufferedImage image = decoder.decodeAsBufferedImage();
					getGraphics().drawImage(image, 0, 0,getWidth(),getHeight(), null);
					TimeUnit.MILLISECONDS.sleep(250);
				} catch (Exception e) {
					break;
				}
			}
			inputStream.close();
			socket.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}
}

Gruß Tom
 
Hallo Tom,
geht das ganze auch im PNG Format ?
Denn JPEG verhunzelt ja bekanntlich alles ...
(schon getestet)
gruß Perikles

EDIT: Andere Formate gingen auch, nur ist der Bildverlust bei mir bei png gleich null, aber über ImageIO laggt das ganze zu stark.
 
Zuletzt bearbeitet:
Zurück