Socket Remote Desktop

stulleman

Bekanntes Mitglied
Guten Tag zusammen!
Ich habe mir überlegt einen Remote Desktop zu schreiben, weil es vom Prinzip ja recht simpel ist.
Der Host wartet auf einen Client und fängt an Screenshots zu senden und empfängt x- und y-Koordinaten von der Clientmaus.
Doch das ist mein Problem. Macht man dafür 2 Verbindungen auf? Eine für die Bilder und eine für die Mauskoordinaten?
Und die Mauskoordinaten, schicke ich die einfach über
Code:
out.print(""+x","+y);
, und splitte das dann beim Server?

Max
 
Zuletzt bearbeitet:

Kr0e

Gesperrter Benutzer
Geht mit Java leider nur sehr begrenzt. Hab ich auch schonmal vor gehabt, aber Java ist dafür von Haus aus nicht geeignet.

Problem: Die Screenshots die du mit Robot z.B. machen kannst, dauern im SChnitt zu lange. Es dauert normalerweise iwas zwischen 80 - 120 ms pro Bild. Damit eine Sequenz vno Bildern flüssig erscheint, brauchst du mindestens 25 FPS aufwärts. Also geht das so nicht, vorallem weil dann noch übrige Rechenzeit hinzukommt: Delta der Bilder berechnen usw.

Was du dafür brauchst ist nativer Zugriff, also DirectX unter Windows, spezielle Biblitoheken (Deren NAme ich nicht kenne) unter Mac und unter Linux vermutlich jenachdem welches GUI du benutzt. Gnome/KDE...


Wenn dir allerdings 10-11 FPS mit fast 100% CPU Last reichen, dann sollte das in der Tat eine sehr einfache Aufgabe sein.


Zu deiner Netzwerkfrage:


Lies dazu einfach Java Netzwerk Tutorials, davon gibts endlos viele. Als Basis wäre vermutlich ein Chat-Beispiel-Programm mit Tutorial hilfreich, der Rest ist dann straight-forward..

Viel Glück,

Gruß,

CHris
 

stulleman

Bekanntes Mitglied
Danke erst mal für die Antwort.
Ich denke ich werde es jetzt trotzdem versuchen, da ich schon angefangen habe zu programmieren ;)

Ich habe jetzt einen Thread der sich um die I/O Streams kümmert.
Output : Bilder und manchmal Text, z.B. Statusmeldungen.
Input: Koordinaten.

Mein Problem: Woher weiß der Client was ihm gesendet wird? Ein Bild oder eine Statusmeldung?
 

stulleman

Bekanntes Mitglied
Antwort: Protokoll! Definiere oder verwende ein Protokoll. z.B.
Byte 0 Nachrichtentyp (1=Bild, 2=Statusmeldung, 3...)
Byte 1 bis 4 Länge der Nachricht in Byte
Byte 5 bis (5+ Wert aus Bytes 1 bis 4) Nachricht/Bild

Ich habe leider keine Ahnung wie das funktioniert!
Ich verstehe was du meinst, habe aber keine Ahnung wie man das umsetzt, vielleicht kannst du mir ja ein Tutorial zeigen oder kurz ein Beispiel geben.
Wäre sehr dankbar dafür!
 

stulleman

Bekanntes Mitglied
Ich bin mir nicht sicher ob du überhaupt gelesen hast was ich geschrieben habe, aber ich habe keine Probleme beim programmieren eines Chats.
Mein Problem liegt bei den Bytes, und wie ich sie zusammenstelle wie hier beschrieben

Antwort: Protokoll! Definiere oder verwende ein Protokoll. z.B.
Byte 0 Nachrichtentyp (1=Bild, 2=Statusmeldung, 3...)
Byte 1 bis 4 Länge der Nachricht in Byte
Byte 5 bis (5+ Wert aus Bytes 1 bis 4) Nachricht/Bild

Und dazu habe ich bei google nichts gefunden was mir helfen könnte!
 

Kr0e

Gesperrter Benutzer
Ich habe gelesen und durchaus verstanden, was du geschrieben hast doch verstehe ich die Schwierighkeit an deinem Vorhaben nicht. Mein Vorredner hats doch erklärt. Stelle präzise Fragen!

-> Nein , du brauchst natürlich nicht 2 Verbindungen, für dieses Vorhaben.

Und mal ehrlich: Wenn du wirklich in der Lage wärst einen Chat zu programmieren, dann wärst auch in der Lage zu verstehen, was mein Vorredner dir vorgeschlagen hat und des Weiteren wüsstest du auch wie du dein Problem lösen könntest. Ich glaube eher, dass DU nicht liest und zuhörst. Geh das Tutorial zum Caht durch. Dort wird ALLES was dein Vorhaben benötigt, erläutert.
 

stulleman

Bekanntes Mitglied
Ich kann dir gerne meine Sourcecode für meine Chat zeigen, der sehr wohl zeigen wird das ich es verstanden habe.
Mein Problem ist wie gesagt das ich nicht weiß wie ich das mit den Bytes lösen kann/soll.
Und irgendwie habe ich das Gefühl das du mir es auch nicht erklären willst ;)

Trotzdem versuche ich mein Problem zu konkretisieren. Ich weiß nicht wie man mit Bytes umgeht, und um ein Bild über ein Socket zu schicken habe ich mir das hier angeguckt: Java J2EE - How to send Image over Socket in Java? und verstehe nicht wie ich das in meinen Code einbauen kann, sodass ich mit 1 und 2 usw. unterscheiden kann was ich verschicke :bahnhof:
 

Kr0e

Gesperrter Benutzer
Nagut, wie verschickt man byte[] arrays übers Netzwerk ?

Wir hätten da einmal die Socket Klasse, welche es dir gestattet Input/Output-Streams zu öffnen. Da du ja sagst, dass du weißt, wie ein Chat geht, setze ich mal voraus, dass du das bereits kennst.


Einen Screenshot bekommst du mit:

Java:
    Robot r = new Robot();
    r.createScreenCapture( ... Maße deines Desktopbereichs als java.awt.Rectangle -> Google ... );

Voilá, so nun musst du die Daten des BufferedImage (Das ist das Objekt, dass dir r.createScreenCapture zurück gibt ;-) ) als byte[] bekommen.

Da gibt es verschiedene Möglichkeiten...

Eine wäre:

Java:
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(screenShotImage, z.b: "png", baos);
    byte[] bytesOut = baos.toByteArray();

Du hast hier den Vorteil, dass es direkt komprimiert wird, was bei Remote Desktop essentiell ist.

So, zurück zum Stream: Du hast nun ein byte[] array, wo sich die Bilddaten drin befinden. Am Besten öffnest du einen DataOutputStream auf dem Socket.getOutputStream(). Damit kannst du dir etw5as Arbeit sparen.

Also:

Java:
    Socket s = blablabla Socket connection usw

    DataOutputStream dos = new DataOutputStream(s.getOutputStream());
 
    dos.writeInt(BildDatenArray.length);
    dos.write(BildDatenArray);

Damit verschickt man dann die reinen Bilddaten, auf der Gegenseite dann natürlich ENTGEGENGESETZT das Gleiche machen.

Das war nun wirklcih die ganze Magie, die dahinter steckt.
 

stulleman

Bekanntes Mitglied
Super herzlichen Dank!
Aber eine Frage bleibt noch, und zwar verstehe ich nicht wieso man die Array length noch vorher schicken muss? Wie gesagt kenne mich halt mit bytes nicht aus ;)
 

Kr0e

Gesperrter Benutzer
Die Länge ist wichtig, woher willst du auf der anderen Seite denn wissen, wieviel zu deinem Bild gehören ? Java stellt das recht gut dar: Ein Stream! Also eine endlose Reihenfolge an Bytes.Es liegt an dem Programmierer dafür zu sorgen, dass diese wirren Bytes auch korrekt interpretiert werden.

Hm, ich denke du solltest dir dann vlt auch was zum Thema Filetransfer anschauen, hab das iwie vorausgesetzt... ^^

Java: copying files over TCP/IP

Hier wird explizit demonstriert, wie man eine Datei (Oder Bild) überträgt.


Vlt als Tipp: Beginn doch einfach bei den Basics. Wenn du nicht wirklich viel Wissen über Netzwerktechnik hast (Das ist wirklihc nicht bös gemeint ;-)), dann wäre es doch für dich wirklich das Beste,vlt nen kleinen FileServer als Grundprojekt zu machen. Damit würden dir viele Fragen später erspart bleiben.

Die nächste Frage wäre vermutlich, warum ein byte[] auf der anderen Seite in mehreren Stücken ankommt usw. Ich meine einfach, dass du noch nicht genug KnowHow hast, um das Problem zu lösen.

Natürlich kannst du hier Fragen stellen, aber Tipps zu geben, bringt meistens nichts, wenn der TO nicht das benötigte Wissen hat, diese auch zu verstehen. IMHO war der Tipp von @Michael... schon ganz gut, aber du wusstest eben nciht, wie du ihn umsetzen sollst...
 

stulleman

Bekanntes Mitglied
Sehe ich genauso ;)
Gut vielleicht werde ich das dann zuerst versuchen, aber ich denke das hat schon viel Licht ins dunkle gebracht ;)

Danke!
 
T

tuxedo

Gast
Geht mit Java leider nur sehr begrenzt. Hab ich auch schonmal vor gehabt, aber Java ist dafür von Haus aus nicht geeignet.

Wenn man das auf "Java Code only" bezieht: Ja.
Aber es gibt da noch JNI ... siehe weiter unten..

Problem: Die Screenshots die du mit Robot z.B. machen kannst, dauern im SChnitt zu lange. Es dauert normalerweise iwas zwischen 80 - 120 ms pro Bild. Damit eine Sequenz vno Bildern flüssig erscheint, brauchst du mindestens 25 FPS aufwärts. Also geht das so nicht, vorallem weil dann noch übrige Rechenzeit hinzukommt: Delta der Bilder berechnen usw.

Das Haupt-Problem am Robot ist, dass das Array, das genutzt wird um die Bilddaten zu transportieren, bei jedem "Snapshot" neu erzeugt wird. Da hat auch der GC jede Menge zu tun... Kann man als eine Art Bug in der Robot-Implementierung sehen. Hab schon versucht das ganze über Reflection "zu korrigieren". Aber da ist soviel "final" und "private", dass man da nicht wirklich bei kommt.

Was du dafür brauchst ist nativer Zugriff, also DirectX unter Windows, spezielle Biblitoheken (Deren NAme ich nicht kenne) unter Mac und unter Linux vermutlich jenachdem welches GUI du benutzt. Gnome/KDE...

Nativer Zugriff, ja. Aber DirectX? Nicht unbedingt. Gibt afaik Methoden in der Windows API um an die Bildinformation zu kommen. Anders macht's der Robot auch nicht. Der erste Schritt wäre hier JNI/JNA.

Unter Linux gibts ähnliche APIs. Da kann an sich sicher am Robot orientieren. Sourcecode gibt's ja. Für jemand der ein wenig mit C++ Umgehen kann, sollte das nicht das riesen problem sein.

Allerdings ist das an die Bildinformation rankommen bei normalen Desktops nicht das Zeitkritische Problem. 4x Full-HD Auflösungen und mehr ... Da wird's dann kritisch, weil es einfach seeeehr viele Daten sind.

Was aber in jedem Fall zeitkritisch ist, ist die "dirty rectangle detection". Also das erkennen der Bildabschnitte die sich seit dem letzten Snapshot geändert haben. Effiziente VNC und RDP Lösungen detektieren das nicht wirklich selbst, sondern hooken sich in die Zeichenroutinen des OS. Damit muss man dann keine Vergleiche zwischen altem und neuem Bild fahren, sondern weiß direkt in welcher Region etwas gezeichnet wurde. Das ganze kann man beliebig komplex weiter spinnen. Gibt da eine ganze Industrie die da dran hängt.

Wenn dir allerdings 10-11 FPS mit fast 100% CPU Last reichen, dann sollte das in der Tat eine sehr einfache Aufgabe sein.

Jo. hab das auch mal gebastelt. Für ne Auflösung von 1280x1024 ging das noch recht gut. Alles darüber wird mit der Robot-Lösung nicht so doll werden. Und je größer der Desktop, desto schwerer wird's auch mit einer optimierten "robot-implementierung".


Gruß
Alex
 

Kr0e

Gesperrter Benutzer
@ Tuxedo:

Ich glaube nicht ,dass es nur an dem von dir beschriebenen Bufferproblem liegt. Das Erstellen von Buffern geht recht fix in Java (Nur wenige ms für einen 1280*1024*4 byte-großen, direkten ByteBuffer). Und obwohl 1280x1024 noch lange kein HD ist, brauchte Robot bei dieser Auflösung 90-100 ms. Nur am Buffer liegt es also nicht.

Du meintest, es wären iwie zu viele Felder final/private... Mit Reflection gibt es ja keine Limiterung, einfahc Field.setAccessible(true) und du kommst an alle Daten dran ;) Ich denke aber sowieso, dass nicht so einfach geht. Und wie gesagt, ich glaube nich, dass das Nichtwiederverwenden des Bildes derartig ins Gewicht schlägt.

Achja, und ich würde sehr wohl DX dafür unter Windows empfehlen. Die normale API ist ähnlcih lahm. Hab das (Als es klar war, dass java.awt.Robot zu langsam ist) mal mit C# gemacht. Das war auch weit entfernt von Optimal. Die Lösung brachte DirectX. Damit hat man direkten Zugriff auf den Desktop.



Unter C# kann man dazu .NET verwenden, was aber im Prinzip auch einfach den WinAPI-Call umwrappt:
(Wie gesagt: Das hier ist nicht sehr viel schneller als die Robot Lösung)

Java:
public Bitmap CaptureScreen()
{
    Bitmap b = new Bitmap(SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height);
    Graphics g = Graphics.FromImage(b);
    g.CopyFromScreen(0, 0, 0, 0, b.Size);
    g.Dispose();
    return b;
}
 
Zuletzt bearbeitet:
T

tuxedo

Gast
Wie sagte schon Morpheus: "Nicht denken, wissen!"

Und ich weiß, dass ich schon ein Bug-Ticket bzgl. Java gesehen habe, in dem genau das so angeprangert wird.

Das Erstellen von Buffern geht recht fix in Java (Nur wenige ms für einen 1280*1024*4 byte-großen, direkten ByteBuffer).

Behaupten kann man viel. Aber wenn man in den Code reinschaut, sieht man, dass kein NIO ByteBuffer verwendet wird, sodern, wenn ich mich recht erinnere, ein int[] ... Und zwischen int[] und ByteBuffer liegen doch Welten, oder etwa nicht?

Du meintest, es wären iwie zu viele Felder final/private... Mit Reflection gibt es ja keine Limiterung, einfahc Field.setAccessible(true) und du kommst an alle Daten dran Ich denke aber sowieso, dass nicht so einfach geht. Und wie gesagt, ich glaube nich, dass das Nichtwiederverwenden des Bildes derartig ins Gewicht schlägt.

Sorry, aber wer von uns beiden hat diesbezüglich schon den JDK Code (nicht das normale src.zip... den JDK Code) angeschaut und auf den Kopf gestellt? Du oder ich? Ach ja, stimmt. Das war ich.... Mit Reflection an eine private Variable zu kommen ist easy. Mit Reflection aber eine final-Methode umbiegen oder anderweitig zugänglich machen ohne den halben Robot neu implementieren zu müssen... Das geht leider nicht ... Und da ist zum teil auch final und Co. dran schuld.

Achja, und ich würde sehr wohl DX dafür unter Windows empfehlen. Die normale API ist ähnlcih lahm. Hab das (Als es klar war, dass java.awt.Robot zu langsam ist) mal mit C# gemacht. Das war auch weit entfernt von Optimal. Die Lösung brachte DirectX. Damit hat man direkten Zugriff auf den Desktop.

"Lahm" ist ein dehnbarer Begriff. Weiß ja nicht wie du's gemacht hast. Aber auch ohne DirectX kommt man an den Grafikspeicher dran. zwar nicht so performant wie mit DirectX, aber auch bei weitem nicht so "lahm" wie der Robot.

Weiß nicht was im C# Code alles dahinter steckt. Aber wenn der die Windows-API genauso schlecht und ineffizient "wrapt" wie der Robot, dann ist klar dasses langsam ist.

- Alex

[update]
Hier der Beleg für meine These:
Bug ID: 5090776 Need more efficient screen capture.

I noticed the creation of the pixel array takes more than %45 of the capture funtion

Das ist genau das, was auch mit mit dem Profiler gesehen habe. Wo hattest du jetzt gleich nochmal gemessen um auf die Ursache zu kommen?
 
Zuletzt bearbeitet von einem Moderator:

Kr0e

Gesperrter Benutzer
Java:
		long d = System.nanoTime();

		int[] ints = new int[1280 * 1024 * 4];

		System.out.println( (System.nanoTime() - d) * 0.000001);

Das Erstellen des int arrays geht doch recht schnell. Klar, das sind 18 ms, die nicht sein müssten, da geb ich dir Recht ;)

Output:
17.953879999999998


Ein Screenshot mit Robot:
108.590205

Sorry, wenn ich nicht immer direkt einen wissenschaftlichen Beweis mitliefere.
 
M

maki

Gast
(Nur wenige ms für einen 1280*1024*4 byte-großen, direkten ByteBuffer)
Das Anlegen von direkten Buffern ist langsamer als bei normalen Arrays, bei letzteren ist das Problem, dass sie vom GC aufgeräumt werden müssen wenn sie nicht wiederverwendet werden können -> langsam
Direkte Buffer sollte man auch wiederverwenden falls möglich, denn ansonsten fällt einem der Geschwindigkeitsunterschied schnell auf.
 
T

tuxedo

Gast
Ist bereits rund 2 Jahre her dass ich mir das zuletzt im Detail angeschaut habe. Scheint sich einiges an der Geschwindigkeit in der JVM intern getan zu haben. Aber die Implementierung ist nach wie vor (seit 1.4.2) gleich. Das Array wird nach wie vor mit jedem Capture neu angelegt. Auch wenn 18ms nach nicht viel aussehen. 16% sind 16%.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
L Remote Desktop per Java steuern Netzwerkprogrammierung 4
K Remote - Desktop Netzwerkprogrammierung 15
K Java RMI bricht ab wenn Remote eine Methode ausgeführt werden soll Netzwerkprogrammierung 5
S .jar läuft local, aber nicht remote (SSH/Terminal) Netzwerkprogrammierung 10
J Prüfen, ob remote UDT Server erreichbar ist Netzwerkprogrammierung 0
K Ansprechen eines Remote Druckers Netzwerkprogrammierung 2
S Socket Remote Administration Tool / Fernwartungsprogramm Netzwerkprogrammierung 9
D Remote-Objekt-Server : Alternative Methodenaufruflogik zu Reflection und hart codiert Netzwerkprogrammierung 5
X SSH Verbindung zu Remote Datenbank Netzwerkprogrammierung 2
J Windows Unix remote Netzwerkprogrammierung 2
W RMI Verschiedene Unterobjekte trotz selbem Remote Object Netzwerkprogrammierung 2
W scan remote UDP port Netzwerkprogrammierung 6
J Socket - Remote/Client Mac-Adresse? Netzwerkprogrammierung 3
G Remote der serialisieren Netzwerkprogrammierung 3
K Remote Shell in Java? Netzwerkprogrammierung 6
R RMI: Remote Object ohne Naming Service benutzen? Netzwerkprogrammierung 2
R PID's auf remote PC unter Windows herrausfinden Netzwerkprogrammierung 2
F Desktop.browse() zugriff verweigert Netzwerkprogrammierung 2
D Java Desktop Mail, vorbereitete Mail Netzwerkprogrammierung 5

Ähnliche Java Themen

Neue Themen


Oben