C# Remote Desktop Programm

Hey Leute,

da ich sonst nirgendswo Hilfe gefunden habe probier ich es mal hier :wink:
Also ich habe ein Remote Desktop Programm geschrieben, welches auch soweit Funktioniert. Es arbeitet mit einem Multithreaded Server und Client. Dazu noch ein Session System um bei anderen zu zuschauen.

So mein Problem ist das die Methode mit der ich ein Screenshot mache nicht die schnellst ist und mir die Größe(also in Bytes) zu groß ist!
Deswegen wollte ich mal Fragen ob hier jemand Erfahrungen mit sowas hat bzw. mir helfen könnte :wink:

Im Moment sind es Etwa mehr als 200k-300k Bytes die mehr als jede Sekunde gesendet werden :confused: Und das ist echt scheisse^^

Die Screenshot Methode:
[CSHARP] public MemoryStream GetScreen()
{
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);

        using (Graphics graphics = Graphics.FromImage(bitmap))
        {
            graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
            Cursors.Default.Draw(graphics, new Rectangle(Cursor.Position, Cursor.Current.Size));
            graphics.Dispose();
        }
        MemoryStream memoryStream = new System.IO.MemoryStream();
        bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);

        bitmap.Dispose();
        memoryStream.Flush();
        memoryStream.Position = 0;
        return memoryStream;
    }[/CSHARP]

Mfg Philip aka JackWhite20

Moin,

ick habe mal was ähnliches versucht. Den Screenshot habe ich aber noch in kleine Raster geteilt und dann geprüft ob sich die Raster geändert haben. Dann habe ich nur die geänderten Raster übertragen. Fraß aber ohne Ende Rechenleistung…

Hey,
mmm ja, so oder so ähnlich macht z.B. TeamViewer das ja auch :confused:
Würdest du mir vielleicht mal zeigen wie du es gelöst hast ? :slight_smile:
Würde mich auch freuen wenn du bock hast drüber zu quatschen :wink:
Wenn du willst kannst du mich ja mal skype adden: jack-white20

@mogel Hast du Pixel für Pixel getestet oder z.B. Histogramm mit Prozent der Veränderung oder ähnliche Verfahren genutzt?

Moin,

habe ich einfach 32x32 oder 64x64 pauschal verglichen. Wenn irgendwo ein Farbwert sich einfach nur geändert hat, habe ich das Rechteck übertragen. Auf dem Monitor ist ja alles Syntetisch bzw. kein Rauschen wie bei einer Kamera. Daher hatte das vom Prinzip super funktioniert.

*** Edit ***

eek Skype - das passt im Forum viel besser

*** Edit ***

ich habe mal den Code in einen Micro-Benchmark gepackt (Laptop: i5/1.7GHz/4Kerne/4GB/IntelHD4000)

[CSHARP]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Drawing;

namespace GrabberDemo
{
public class Program
{
///


/// Der Haupteinstiegspunkt für die Anwendung.
///

[STAThread]
static void Main() {
new Program();
}

    private bool ende = false;
    private int rounds = 0;
    private int time = 0;
    private int min = 10000;
    private int max = 0;

    public Program()
    {
        Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
        while (!ende && rounds++ < 10000)
        {
            DateTime start = DateTime.Now;
            GetScreen();
            DateTime stopp = DateTime.Now;
            int ms = stopp.Subtract(start).Milliseconds;
            time += ms;
            if (min > ms) min = ms;
            if (max < ms) max = ms;
            Debug.WriteLine("TIME: " + ms + "ms");
        }
        Debug.WriteLine("MEAN: " + (time / rounds) + "ms - min/max: " + min + "/" + max);
    }

    void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
    {
        Debug.WriteLine("CTRL-C detected");
        ende = true;
    }

    public MemoryStream GetScreen()
    {
        Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);

        using (Graphics graphics = Graphics.FromImage(bitmap))
        {
            graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
            Cursors.Default.Draw(graphics, new Rectangle(Cursor.Position, Cursor.Current.Size));
            graphics.Dispose();
        }

        bitmap.Dispose();
        //MemoryStream memoryStream = new System.IO.MemoryStream();
        //bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);

        //bitmap.Dispose();
        //memoryStream.Flush();
        //memoryStream.Position = 0;
        //return memoryStream;
        return null;
    }
}

}
[/CSHARP]

das konvertieren des Bildes in JPEG kostet auf meinem Laptop ca. 25ms. Das kann auch raus, da die Daten vorher eh noch geprüft werden (was bei JPEG zusätzlich Rechenleistung kostet).


MEAN: 53ms - min/max: 37/101

der Peak kommt (vermutlich) von Alt-tab, also Windows Neuaufbau. Ich hatte zumindest ein paar mal mit Absicht gedrückt.

allerdings ist ein Deinem Code ein klassischer Memory-Leak enthalten. Du verwendest (indirekt) nicht verwaltet Resourcen. D.h. das Du die resourcen wieder frei geben musst, wenn Du sie nicht mehr benötigst bitmap.Dispose(); (in vernüftigen Sprache gibt es dafür einen Destruktor). Den zweiten Memory-Leak hast (wahrscheinlich unwissend) erfolgreich umschifft, using(blabla ....

Danke für die etwas nettere Hilfe hier :wink:
Ich hab mich gestern nochmal hingesetzt und es mir alles genau vorgestellt und aufgezeichnet.
Hab jetzt einen guten Lösungsansatz der auch schon Funktioniert(Nur noch ein paar Optimierungen) :wink:

Also trotzdem nochmal danke :wink:

Mfg Philip

PS: Wenn ich es komplett optimiert habe etc werde ich es wahrscheinlich hier vorstellen bzw. Posten :slight_smile:

Moin,

ich habe jetzt nochmal ein bischen rumgespielt und haben einen Screenshot mit WinAPI verwendet. Das ganze habe ich über eine DLL via C++/CLI eingebunden.

MEAN: 3ms - min/max: 3/13

Ich bin mir bei den Werten nicht so ganz sicher. Meine letzte Info war das Windows einen Auflösung von 16ms hat - Stand ist allerdings XP. Unter Win7 habe ich bisher nix gehabt wo ich auf Millisekuden timen musste. Sollten die Werte richtig sein (10000 Zyklen), dann ist die WinAPI an der Stelle wirklich zu bevorzugen :slight_smile:

Hey,
würdest du die Methode mal rein posten ? Weil ich benutze die Standard Methode die ich oben schon gepostet habe.Die brauch halt sehr sehr lang^^

Noch was:
Im lokalen Netzwerk funzt es echt super nice und schnell(wäre einiges besser wenn die Screenshot Methode schneller wäre etc^^), aber trotz der Bildschirm Unterteilung braucht ein update immer noch so 40k(teilweise auch nur 20k oder so^^) Bytes. Kennt einer da eine gut Methode fürs komprimieren, ohne die Bytes zu „beschädigen“ etc ?
Wenn der Server auf meinem Root läuft und ich mein Laptop senden lass und mein pc empfangen dann geht es auch aber da ist halt nen größeres delay, wegen der Byte Größe und der Image Methode :confused:

Hier mal nen Screen von Heut Abend :wink:

:slight_smile:

Ja das habe ich gesehen nachdem ich schon mit schreiben fertig war :stuck_out_tongue:

Was ist denn mit dem hier:
Im lokalen Netzwerk funzt es echt super nice und schnell(wäre einiges besser wenn die Screenshot Methode schneller wäre etc^^), aber trotz der Bildschirm Unterteilung braucht ein update immer noch so 40k(teilweise auch nur 20k oder so^^) Bytes. Kennt einer da eine gut Methode fürs komprimieren, ohne die Bytes zu „beschädigen“ etc ?
Wenn der Server auf meinem Root läuft und ich mein Laptop senden lass und mein pc empfangen dann geht es auch aber da ist halt nen größeres delay, wegen der Byte Größe und der Image Methode :confused:

Gibt es da ne gute compression/decompression API/Lösung für ? :slight_smile:

*** Edit ***

Mmm,
also irgendwie will er bei mir bereiche nicht „screenshotten“.
Denn wenn ich das hier mache, kommt nur ein schwarzes Bild:

[CSHARP]BitBlt(mem, 500, 500, meineBreite, meineHöhe, dsk, 0, 0, 13369376);[/CSHARP]

Full Screen geht und ne gewissen Größe von x und y auch, aber sobald die bestimmte Größe von x und y überschritten ist, geht es nicht mehr :confused:

Haste ne Idee mogel ?

*** Edit ***

Das Problem hab ich gelöst :wink: Hab 2 Parameter vertauscht durch die komische Benennung^^ :stuck_out_tongue:

Im raum bleibt immer noch die Frage wegen der Byte Größe :confused:

Hat vielleicht einer eine Idee wieso sowas auftritt ?:

Manchmal gar nicht und manchmal ziemlich oft^^ Ist nicht immer unten, auch nicht immer zwei sonder ehr so einzel stücke :confused:

sieht nach einem Thread/Sync Problem aus - oder Du greifst auf falschen Speicher zu

Naja Thread Fehler eig. nicht. Ich denke auch das das nen Sende Fehler ist ist auch erst so stark nachdem ich was geändert habe :confused: Ich lese jetzt den Binaryreader nicht mehr bis zum Schluss aus sondern sende die länge des letzten Stücks was ich senden muss und lese dann halt ReadBytes(länge) aus. Aber ich verstehe nicht wieso das daran liegen sollte da das ja der sauberere weg ist^^
Ne Idee vielleicht ?

Wegen dem Problem mit dem vielen Bytes:
Ich könnte machen das unter 5-10k nur gesendet werden nur da kriege ich Probleme beim Multithreading…der Haupt Thread braucht 25-30cpu, und wenn ich jetzt 16 hätte naja…kann man sich ja denken :open_mouth:
Im Moment gehe ich halt alle x und y Felder durch in diesem Main Thread das Problem daran ist das ich die Unterteilungen nicht höher stellen kann, da sonst vom ersten bis zum zb. 16. lange dauern würde und er das dazwischen nicht richtig überprüfen kann :confused:
Hast du oder ein anderer ne gute schnelle Lösung das anders zu machen ? Ich muss halt durch alle x,y coords durchgehen…:confused:

vergleich doch mal die alte Sendemethode mit der neuen Sendemethode - oder - verwende wieder die Alte und bau darauf eine ganz neue Sendemethode. Sofern Du vorher immer die richtige Länge sendest, liegt es nicht am Senden und Emfpangen. Eher am Einpacken oder Auspacken der Daten.

Wozu so viele Threads? Bau doch das ganze erstmal stabil bevor Du am Fine-Tuning rumbastelst. Außerdem verballerst Du die gesamte CPU für einen Dienst und kannst dann nicht mehr Remote Arbeiten. Was das Programm völlig sinnlos macht.

Dann machst Du etwas falsch (oder meine Tests waren falsch). Ich hatte angefangen das Ganze ebenfalls zu unterteilen in ZxZ große Felder. Dabei war es egal ob Z nur 16 Pixel breit war oder 256 Pixel. Das ganze System verhielt sich wie O(n). Allerdings waren rund 400ms für den kleinen Screen nicht sehr berauschend -.-

[QUOTE=mogel]vergleich doch mal die alte Sendemethode mit der neuen Sendemethode - oder - verwende wieder die Alte und bau darauf eine ganz neue Sendemethode. Sofern Du vorher immer die richtige Länge sendest, liegt es nicht am Senden und Emfpangen. Eher am Einpacken oder Auspacken der Daten.

Wozu so viele Threads? Bau doch das ganze erstmal stabil bevor Du am Fine-Tuning rumbastelst. Außerdem verballerst Du die gesamte CPU für einen Dienst und kannst dann nicht mehr Remote Arbeiten. Was das Programm völlig sinnlos macht.

Dann machst Du etwas falsch (oder meine Tests waren falsch). Ich hatte angefangen das Ganze ebenfalls zu unterteilen in ZxZ große Felder. Dabei war es egal ob Z nur 16 Pixel breit war oder 256 Pixel. Das ganze System verhielt sich wie O(n). Allerdings waren rund 400ms für den kleinen Screen nicht sehr berauschend -.-[/QUOTE]

Naja ich nutze einfach meine „alte“ Methode^^ Die bewirkt quasi das gleiche und ist auch nicht langsamer etc :wink:

Wieso kann ich nicht mehr Remote Arbeiten ? Natürlich geht das^^

Wie gehst du denn alle Aufteilungen ab, sodass sich das immer gleich schnell verhält egal wie die Aufteilung ist ?

je mehr sich der Remoterechner mit der CPU den 100% nähert, um so schwieriger wird das Arbeiten - ist bei lokalen Rechnern genau so :slight_smile:

etwa so


for(int rx = 0; rx < maxrasterx; rx++) {
	for(int ry = 0; ry < maxrastery; ry++) {
		int deltax = rx * rastersizex;
		int deltay = ry * rastersizey;
		boolean changed = false;
		for(int x = 0; x < rastersizex; x++) {
			for(int y = 0; y < rastersizey; y++) {
				int px = deltax + x;
				int py = deltay + y;
				// (px,py) aus Screenshot mit letztem Framevergleichen
				// wenn er sich geändert hat, dann changed = true
			}
		}
		if (changed) {
			// aktuellen Frame über das Netzwerk pusten
		}
	}
}

warum sendet Ihr die Objekte (Bitmap) nicht direkt als bytes ? und wandelt es dann wieder zu einem Bitmap um ? würde doch auch gehen.

Naja du machst ja auch nix in deine Methode -_-
Und du gehst doch selber durch alle durch, und du hast sogar 4 For Loops…^^

Hä ? Ich sende doch Bytes…

ja aber du kannst mit dem BinnaryFormatter ein Object egal welches in ein Byte Array Umwandeln, somit hast du keine 4 Schleifen. Schau mal hier http://www.morgantechspace.com/2013/08/convert-object-to-byte-array-and-vice.html

*** Edit ***

und du musst nicht jedes bild einzeln Umwandeln etc.

Hä ? Ich glaube du hast noch nicht so ganz verstanden was ich mache bzw. wie es geht oder ?
Ich brauche nix zum Umwandeln, das ist ja nicht mein Problem…^^
Was haben die Schleifen damit zu tun ?