Benutzer mit den meisten Antworten
TcpClient / Bildschirmübertragung / Packets zu gross

Frage
-
Hallo liebes msdn Forum,
Ich bin dabei einen Bildschirmübertragungs-client & Server zu programmieren. Die Verbindung und das authentifizieren funktionieren. Wenn ich allerdings Versuche das Bild als einzelnes Packet zu veschicken kommt es zu einer OutOfMemoryException.
Hier der Code zum verschicken des Bildes:
// In der RemoteDesktop-Klasse private void Capture() { Bitmap bmp = CaptureScreen.CaptureDesktopWithCursor(); bmp = new Bitmap(bmp, new Size(960, 540)); client.Protocol.SendScreen(bmp); } // In der Protocol-Klasse public void SendScreen(Bitmap bmp) { MemoryStream memoryStream = new MemoryStream(); bmp.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png); bmp.Dispose(); byte[] package = memoryStream.ToArray(); Send(8, package); // Packet-ID = 8 } private bool Send(Int16 packet, byte[] content) { return SendBytes(BitConverter.GetBytes(packet), content); } private bool SendBytes(byte[] packetNo, byte[] send) { try { // Get Packet Length int bytes = send.Length + 6; byte[] length = BitConverter.GetBytes(bytes); // Write Packet netStream.Write(length, 0, 4); netStream.Write(packetNo, 0, 2); netStream.Write(send, 0, send.Length); netStream.Flush(); return true; } catch { return false; } }
Und das Gegenstück zum Empfangen
private void Read(IAsyncResult ar) { try { // get buffer size int buffer = tcp.ReceiveBufferSize; if (buffer >= 6) { byte[] size = new byte[4]; netStream.Read(size, 0, 4); int packLen = BitConverter.ToInt32(size, 0) - 4; // create buffer array byte[] read = new byte[packLen]; // read stream to buffer netStream.Read(read, 0, packLen); // handle ReceivedEvent(this, read); } // start async read tcp.GetStream().BeginRead(new byte[] { 0 }, 0, 0, Read, null); } catch (Exception) { DisconnectedEvent(this, "Fehler beim lesen des Streams"); } } // Daraufhin wird überprüft ob der Client verifiziert ist, und das Packet gehandlet. public bool Handle(byte[] recv) { // Create Packet number / header byte[] pack = new byte[] { recv[0], recv[1] }; Int16 recvHeader = BitConverter.ToInt16(pack, 0); // Create Packet Content int bytesToEliminate = 2; int newLength = recv.Length - bytesToEliminate; byte[] recvContent = new byte[newLength]; Array.Copy(recv, bytesToEliminate, recvContent, 0, newLength); string message = ""; if (!skipMessageBuilding.Contains(recvHeader)) message = ByteHelper.GetString(recvContent); switch (recvHeader) { case 8: NewScreenEvent(recvContent); break; } }
Da Ich noch nicht sehr viel mit Netzwerkprogrammierung gearbeitet habe wäre ich für jeden Tipp dankbar ^^
Hauptsächlich würde es darum gehen, wie ich die OutOfMemory-Exception verhindern kann bzw ob es sinn Macht die Packete zu teilen und wenn ja wie das am einfachsten geht. MfG. Basic
Antworten
-
die OutMemoryException dürfte vor allem daraus resultieren, dass Du großzügig mit Byte-Arrays umgehst. Vor allem unter 32-Bit wird dabei schnell der Speicher eng, zumal große Arrays (> 85KB) im sog. Large Object Heap (LOH)[1] verwaltet werden und was zur Fragmentierung führt und längerfristig wiederum eine OOM Ausnahme verursachen kann.
Bei einer IP Netzwerkübertragung werden die Daten ohnehin in kleinere Blöcke aufgeteilt (siehe u. a. MTU), weswegen man größere Blöcke in mehrere Schreibvorgänge aufteilen sollte. Der TcpClient verwendet z. B. 8192 Bytes (8KB) im Standard dafür dafür. Wenn man das berücksichtigt, kann man den Speicherbedarf deutlich verringern.
Wenn Du Paketweise überträgst, kannst du den MemoryStream direkt verwenden, in dem Du in an den Anfang stellst und via Stream.CopyTo überträgst - alternativ schreibt MemoryStream.WriteTo den kompletten Inhalt. Sollte es trotz allem zu eng mit dem Speicher werden, verwende eine temporäre Datei anstatt des MemoryStreams.
Auf der Empfangsseite (Read) kommen die Pakete ggf. wiederum geteilt an - es ist nicht garantiert, dass bis zum Maximum gelesen wird, vielmehr sollte man immer die Rückgabe (= effektive Länge) von Read auswerten und weiter verwenden.
In den Beispielen zu C# in a Nutshell findest Du einige Implementierungen, die Du für asynchrones Senden und Empfangen als Basis nehmen kannst.
Gruß Elmar
[1] http://blogs.msdn.com/b/dotnet/archive/2011/10/04/large-object-heap-improvements-in-net-4-5.aspx
- Als Antwort vorgeschlagen Aleksander Chalabashiev Montag, 13. Oktober 2014 06:26
- Als Antwort markiert Aleksander Chalabashiev Montag, 20. Oktober 2014 09:18