TCP: Datei senden (mit Statusanzeige)

    • VB.NET
    • .NET (FX) 4.5–4.8

    Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von Radinator.

      TCP: Datei senden (mit Statusanzeige)

      Jo,
      wie @radio-ffk versprochen hier mal der Code, um eine Datei über TCP zu versenden. Dafür wird die Datei in kleine Pakete eingeteilt und dann häppchenweise verschickt. Das hat den Vorteil, dass wird nicht die komplette Datei in den Arbeitsspeicher laden müssen. Ein Beispielprojekt ist im Anhang. Die Idee stammt von hier. Viel Spaß :)

      Client, Senden:

      VB.NET-Quellcode

      1. Const BufferSize = 1024
      2. Private Async Sub SendButton_Click(sender As Object, e As EventArgs) Handles SendButton.Click
      3. Dim port As Integer
      4. 'Erstmal überprüfen wir die Benutzereingaben
      5. If String.IsNullOrWhiteSpace(IpTextBox.Text) Then
      6. MessageBox.Show("Bitte geben Sie eine IP-Adresse ein", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
      7. Return
      8. End If
      9. If Not Integer.TryParse(PortTextBox.Text, port) OrElse (port < 1 OrElse port > 65535) Then
      10. MessageBox.Show("Bitte geben Sie einen gültigen Port ein", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
      11. Return
      12. End If
      13. 'Wenn alles ok ist, deaktivieren wir alle Buttons
      14. SendButton.Enabled = False
      15. IpTextBox.Enabled = False
      16. PortTextBox.Enabled = False
      17. SelectPathButton.Enabled = False
      18. Dim tcpClient As New TcpClient
      19. StatusLabel.Text = "Verbinde zu Server..."
      20. Try
      21. Await tcpClient.ConnectAsync(IpTextBox.Text, port) 'Wir versuchen, eine Verbindung zu dem Server aufzubauen
      22. Catch ex As SocketException
      23. MessageBox.Show("Es konnte keine Verbindung zu dem Server hergestellt werden") 'Wenn das nicht klappt, sagen wir das dem Benutzer und brechen ab
      24. ResetSending()
      25. Return
      26. End Try
      27. Using binaryWriter = New BinaryWriter(tcpClient.GetStream()) 'BinaryWriter sind das beste. Also instanziieren wir uns einen
      28. Using fs = New FileStream(PathTextBox.Text, FileMode.Open, FileAccess.Read) 'und wir öffnen die Datei mit Rechten zum Auslesen
      29. Dim packets = Convert.ToInt32(Math.Ceiling(fs.Length / BufferSize)) 'Wir berechnen, wie viele Pakete wir brauchen werden. Ein Paket kann maximal die Größe des Buffers haben
      30. Dim remainingBytes = CInt(fs.Length) 'Die Anzahl der Bytes, die wir noch versenden müssen
      31. StatusProgressbar.Maximum = packets
      32. binaryWriter.Write(remainingBytes) 'Wir fangen an, indem wir dem Server die Größe der Datei mitteilen
      33. For i = 0 To packets - 1
      34. Dim currentPacketLength As Integer 'Dies ist die Größe des aktuellen Paketes, welches wir verschicken wollen
      35. If remainingBytes > BufferSize Then 'Wenn noch genug Bytes für ein volles Paket da sind, nehmen wir direkt die Größe...
      36. currentPacketLength = BufferSize
      37. remainingBytes -= currentPacketLength '... und subtrahieren dies von den remainingBytes
      38. Else
      39. currentPacketLength = remainingBytes 'Das wird wohl das letzte Paket sein, zumindest immer dann, wenn es nicht absolut perkekt passt
      40. remainingBytes = 0
      41. End If
      42. Dim sendingBuffer = New Byte(currentPacketLength - 1) {} 'Wir definieren unseren Buffer mit der Größe, die wir weiter oben ja bestimmt haben...
      43. Await fs.ReadAsync(sendingBuffer, 0, currentPacketLength) '... lesen diese ...
      44. Await Task.Run(Sub() binaryWriter.Write(sendingBuffer, 0, sendingBuffer.Length)) '... und verschicken diese
      45. StatusProgressbar.Value = i 'Noch schön dem Benutzer zeigen, was man geschafft hat
      46. StatusLabel.Text = String.Format("{0} KiB von {1} KiB", (fs.Length - remainingBytes) \ 1024, fs.Length \ 1024)
      47. Next
      48. End Using
      49. End Using
      50. MessageBox.Show("Die Datei wurde erfolgreich übertragen")
      51. ResetSending()
      52. End Sub
      53. Private Sub ResetSending()
      54. SendButton.Enabled = True
      55. PortTextBox.Enabled = True
      56. IpTextBox.Enabled = True
      57. SelectPathButton.Enabled = True
      58. StatusLabel.Text = String.Empty
      59. StatusProgressbar.Value = 0
      60. End Sub


      Server, Empfangen:

      VB.NET-Quellcode

      1. Imports System.IO
      2. Imports System.Net
      3. Imports System.Net.Sockets
      4. Module Module1
      5. Const Port As Integer = 10898
      6. Const BufferSize = 1024
      7. Sub Main()
      8. Dim listener = New TcpListener(IPAddress.Any, Port) 'Wir instanziieren und starten den Listener
      9. listener.Start()
      10. Console.WriteLine("Der Server wurde gestartet und wartet auf Verbindungen.")
      11. While True
      12. Dim client = listener.AcceptTcpClient() 'Wir warten auf eine neue Verbindung
      13. Try
      14. Using binaryReader = New BinaryReader(client.GetStream()) 'und holen uns einen BinaryReader, das Gegenstück des BinaryWriters
      15. Console.WriteLine("Verbindung zu Client hergestellt")
      16. Dim fileLength = binaryReader.ReadInt32() 'Wir empfangen die Größe der Datei...
      17. Dim packets = Convert.ToInt32(Math.Ceiling(fileLength / BufferSize)) '... damit wir die Anzahl der zu empfangenen Pakete ausrechnen können
      18. Console.WriteLine("Datei wird empfangen. Größe: {0} KiB ({1} Pakete)", fileLength \ 1024, packets)
      19. Dim remainingBytes = fileLength 'Die Anzahl der Bytes, die wir noch empfangen müssen
      20. Using fs = New FileStream("file.fi", FileMode.Create, FileAccess.Write) 'Wir öffnen erstmal einen neuen FileStream mit Schreibrechten
      21. For i = 0 To packets - 1
      22. Dim currentPacketLength As Integer 'Dies ist die Größe des aktuellen Paketes, welches wir empfangen wollen
      23. If remainingBytes > BufferSize Then 'Wenn noch genug Bytes für ein volles Paket da sind, nehmen wir direkt die Größe...
      24. currentPacketLength = BufferSize
      25. remainingBytes -= currentPacketLength '... und subtrahieren dies von den remainingBytes
      26. Else
      27. currentPacketLength = remainingBytes 'Das wird wohl das letzte Paket sein, zumindest immer dann, wenn es nicht absolut perkekt passt
      28. remainingBytes = 0
      29. End If
      30. Dim receivingBuffer = binaryReader.ReadBytes(currentPacketLength) 'Wir empfangen die Bytes in der Größe des aktuellen Pakets (currentPacketLength)
      31. fs.Write(receivingBuffer, 0, receivingBuffer.Length) 'und schreiben dies direkt in den FileStream
      32. Console.Write("{2}{0} KiB von {1} KiB", (fileLength - remainingBytes) \ 1024, fileLength \ 1024, vbCr)
      33. Next
      34. End Using
      35. End Using
      36. Console.WriteLine()
      37. Console.WriteLine("Die Datei wurde erfolgreich übertragen. Die Verbindung wird nun geschlossen")
      38. Catch ex As Exception
      39. Console.WriteLine("Ein Fehler ist aufgetreten: {0}", ex.Message)
      40. End Try
      41. client.Close()
      42. End While
      43. End Sub
      44. End Module
      Dateien
      Mfg
      Vincent

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VincentTB“ ()

      @VincentTB Danke erstmal. Nun zur Sache:

      Code 1, Zeile 34 und 35:
      Ein Using-Operand vom Typ "Object" muss System.IDisposable implementieren.

      Code 1, Zeile 27:
      "ConnectAsync" ist kein Member von "System.Net.Sockets.TcpClient".

      Code 1, Zeile 54:
      "Run" ist kein Member von "System.Threading.Tasks.Task".

      Irgendeine Lösung dafür?
      Scheint als würde da der Datentyp fehlen. Weiß nicht inwiefern das Option Infer in VB so regeln würde, gib einfach noch As BinaryWriter an oder verbinde beides gleich ohne =.

      Task.Run gibt es erst seit 4.5, nimm das Äquivalent Task.Factory.StartNew oder TaskEx.Run mit Microsoft.Bcl.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      @radio-ffk
      Der Code benötigt das .Net Framework 4.5. Aber das kannst du ganz einfach runterschrauben, indem du das ganze durch die nicht asynchronen Sachen ersetzt, also .ConnectAsync() -> .Connect(), fs.ReadAsync() -> fs.Read() und Await Task.Run(Sub() binaryWriter.Write()) -> binaryWriter.Write(). Dann musst du das ganze in einem Thread machen, sonst würde sich das GUI aufhängen.
      Mfg
      Vincent

      Auch das Async im Sub sowie das Await vor fs.Read weg?

      Edit: Ja ^^

      Edit 2: Wie kann ich die Pakete durchreichen? Also vom Server an alle Clients weiterleiten, statt am Server zu speichern.

      Edit 3: Wenn ich am Server versuche einen zweiten Listener zu erstellen, funktioniert der Erste nicht mehr. Obwohl verschiedene Ports eingestellt sind.

      Quellcode

      1. Ein Ausnahmefehler des Typs "System.Net.Sockets.SocketException" ist in System.dll aufgetreten.
      2. Zusätzliche Informationen: Normalerweise darf jede Socketadresse (Protokoll, Netzwerkadresse oder Anschluss) nur jeweils einmal verwendet werden

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „radio-ffk“ ()

      VincentTB schrieb:

      VB.NET-Quellcode

      1. Dim sendingBuffer = New Byte(currentPacketLength - 1) {}
      2. Await fs.ReadAsync(sendingBuffer, 0, currentPacketLength)

      Sicher, dass man das noch um 1 subtrahieren muss? Weil du dann 1024 Bytes sendest aber nur 1023 Bytes in den Buffer/in das Byte-Array reinpassen, was wiederum eine Exception auslöst:

      Quellcode

      1. Eine Ausnahme (erste Chance) des Typs "System.ArgumentException" ist in mscorlib.dll aufgetreten.
      2. Zusätzliche Informationen: Offset und Länge für das Array liegen außerhalb des gültigen Bereichs, oder die Anzahl ist größer als die Anzahl der Elemente vom Index bis zum Ende der Quellauflistung.
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      @radio-ffk Einfach weitersenden?
      "Life isn't about winning the race. Life is about finishing the race and how many people we can help finish the race." ~Marc Mero

      Nun bin ich also auch soweit: Keine VB-Fragen per PM! Es gibt hier ein Forum, verdammt!
      @KaskadekingDE
      Jap, das ist in VB ganz komisch. Wenn du = New Byte(1) schreibst, hat das Array 2 Elemente:


      @radio-ffk
      Du solltest ein ID-System einführen. Beispiel: Jeder Client hat eine ID. Eine ID ist 3 Bytes groß (also können dann maximal 256^3 (= 16777216) Clients verbinden, sollte aber denke ich reichen). Jeder Client bekommt nach dem erfolgreichen Verbinden eine ID von dem Server zugewiesen. Angenommen Client a möchte Client b eine Nachricht senden. Dann ist der Befehl so aufgebaut: [Erstes Byte sagt, dass dies eine Nachricht ist, die an genau einen Empfänger geht][Die nächsten 3 Bytes sagen, an wen die Nachricht geht][Jetzt folgt die kodierte Nachricht]. Wenn jetzt jemand zB eine Datei senden will, ist das erste Byte zB. 0, dann kommt das Token des Client und anschließend das Paket.

      Also einfach das erste Byte jeder empfangenen Bytefolge sagt den Verwendungszweck aus, zB 0 für Nachricht an einen Empfänger, 1 für Nachricht an alle in einer bestimmten Gruppe, 2 für eine Nachricht für alle, 3 für ein Bild usw. Wenn du mehr als 256 Befehle willst, solltest du vielleicht zwei Bytes verwenden, um den Verwendungszweck der Nachricht zu definieren. Dann folgen die Parameter, die dann für jeden Verwendungszweck anders ausgelesen werden. Wenn zB. das erste Byte, das Token, 0 (=Nachricht an einen Empfänger) ist, dann weißt du, das die nächsten 3 Bytes die Empfänger ID enthalten und alle Bytes danach dann den kodierten Text enthalten.

      So würde ich mir sowas vorstellen bzw. so habe ich das bisher umgesetzt.
      Mfg
      Vincent

      @VincentTB der Chat hat ja ein ID-System. Nur ist die Frage ob ich alle normalen StreamReader und Writer durch NetworkStreams und BinaryReader/Writer ersetzen soll, oder ich beide (StreamR/W und BinaryR/W) auf einem Stream laufen lassen kann.

      VincentTB schrieb:

      Jap, das ist in VB ganz komisch. Wenn du = New Byte(1) schreibst, hat das Array 2 Elemente:

      Ok ^^ Hab den Code nähmlich nach C# übersetzt (ja ich weiß der war bereits C# bei CodeProject, deiner sah aber besser aus :) ) und da hat er bei mir rumgemeckert.
      Außerdem wollte ich das ganze ein wenig ausbauen und so machen, dass man mehrere Dateien auf einmal senden kann und der Server diese nacheinander abarbeitet.
      Funktioniert aber irgendwie nicht denn alle Dateien sind beschädigt nach der Übertragung. Die erste geh "halbwegs" noch. Als Test hab ich mal 2. JPG's genommen die 1. wird zwar angezeigt ist aber unten am Rand des Bildes beschädigt (s. Anhang) und die 2. wird gar nicht angezeigt.

      Hab mir also mal von jeden Paket den Hash angeguckt und gesehen, dass bei der 1. Datei beim Server 1 Paket mehr ankommt als der Client sendet und der Rest der Packets von den anderen Dateien alle falsch sind.
      SHA1-Hashes

      Quellcode

      1. # Sender (Client) | # Empfänger (Server)
      2. Datei 1 (JPG) |
      3. Packet Hash: b17a0fe60659de92691588af11dbab3913281766 | Packet Hash: b17a0fe60659de92691588af11dbab3913281766
      4. Packet Hash: 73727128df199351b7dede92d5c1ec8dfab43496 | Packet Hash: 73727128df199351b7dede92d5c1ec8dfab43496
      5. Packet Hash: b36123acb6a8b713de310742427f2aabddebf465 | Packet Hash: b36123acb6a8b713de310742427f2aabddebf465
      6. Packet Hash: 50ebf7ebd2ddfc726aff59713a3424a526c1fa8a | Packet Hash: 50ebf7ebd2ddfc726aff59713a3424a526c1fa8a
      7. Packet Hash: 77d2df23ec1a8ee096a8f81999c8efc813c6480d | Packet Hash: 77d2df23ec1a8ee096a8f81999c8efc813c6480d
      8. Packet Hash: 653e4978c3f7e71063ae01db98e88a2b85b70610 | Packet Hash: 653e4978c3f7e71063ae01db98e88a2b85b70610
      9. Packet Hash: 7361585d221f35eebc0fc967dc989054f026d6ab | Packet Hash: 7361585d221f35eebc0fc967dc989054f026d6ab
      10. Packet Hash: 841e4e9dd62f908690bae7be4b780e42038814a2 | Packet Hash: 841e4e9dd62f908690bae7be4b780e42038814a2
      11. Packet Hash: fce4ec3c2ee9d4559e9c59415a23ff9ba843ae66 | Packet Hash: fce4ec3c2ee9d4559e9c59415a23ff9ba843ae66
      12. Packet Hash: b1ef23d13fedbcca1c6dd001af955f4831b8ec9c | Packet Hash: b1ef23d13fedbcca1c6dd001af955f4831b8ec9c
      13. Packet Hash: --- * | Packet Hash: 90c0516019f19a1de4e9679ca97c5b9141711e55
      14. * Das Paket wurde gar nicht vom Client gesendet aber trotzdem wurde eins empfangen
      15. Datei 2 (JPG)
      16. Packet Hash: 8058420b87935c1ad3a4bc0175901695f0fedb4e | Packet Hash: 76da753204130abe036b7b785dce013c37d4b334
      17. Packet Hash: b76be2aeb9fe6ecd0091c0f214d98f0cd241337f | Packet Hash: c72477bcf7fd6a5acf8acbe71148116d50156ad0
      18. Packet Hash: 5b7cfb22e22639f2ff889e45ee33726370444dbf | Packet Hash: af52d35fad0be47b373dc210b912c7fec10d3c6d
      19. Packet Hash: e5413389554fc5ff73cb81ac3309f320e84ef233 | Packet Hash: da39a3ee5e6b4b0d3255bfef95601890afd80709


      Und hier mein Code:
      Spoiler anzeigen

      Empfänger

      C#-Quellcode

      1. try
      2. {
      3. using (var binaryReader = new BinaryReader(client.GetStream()))
      4. {
      5. var sInfos = binaryReader.ReadString();
      6. TransferInfos infos;
      7. var serializer = new XmlSerializer(typeof (TransferInfos));
      8. using (var sr = new StringReader(sInfos))
      9. {
      10. infos = (TransferInfos) serializer.Deserialize(sr); // Deserialisiere den empfangenen String in eine Klasse
      11. }
      12. Trace.WriteLine("User {0} connected. Retrieving file list...", infos.Id);
      13. if (ApplicationConfig.UseAuthentification && infos.Password != ApplicationConfig.Password)
      14. {
      15. Trace.WriteLine("{0} failed to authorize/connect to server: Wrong password");
      16. client.Close();
      17. continue;
      18. }
      19. Trace.WriteLine(string.Format("Transfering {0} file(s)...", infos.TotalFiles));
      20. var time = DateTime.Now.ToString("HH.mm.ss_yyyy.M.d");
      21. var dir = "files\\" + time;
      22. if (!Directory.Exists(dir))
      23. {
      24. Directory.CreateDirectory(dir);
      25. }
      26. for (var fileIndex = 0; fileIndex <= infos.TotalFiles - 1; fileIndex++)
      27. {
      28. var file = infos.Files[fileIndex];
      29. var packets = Convert.ToInt32(Math.Ceiling((decimal) file.FileSize/BufferSize));
      30. Trace.WriteLine(string.Format("File {0} of {1}", fileIndex + 1, infos.TotalFiles));
      31. Trace.WriteLine(string.Format("Size: {0} KiB ({1} packets)", file.FileSize, packets));
      32. var remainingBytes = file.FileSize;
      33. var filePath = dir + "\\" + file.FileName;
      34. using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
      35. {
      36. for (var i = 0; i <= packets - 1; i++)
      37. {
      38. int currentPacketLength;
      39. if (remainingBytes > BufferSize)
      40. {
      41. currentPacketLength = BufferSize;
      42. remainingBytes -= currentPacketLength;
      43. }
      44. else
      45. {
      46. currentPacketLength = remainingBytes;
      47. remainingBytes = 0;
      48. }
      49. var receivingBuffer = binaryReader.ReadBytes(currentPacketLength);
      50. fs.Write(receivingBuffer, 0, receivingBuffer.Length);
      51. //Trace.WriteLine("Transfered {0} KiB of {1} KiB",
      52. //(file.FileSize - remainingBytes) / 1024, file.FileSize / 1024);
      53. }
      54. }
      55. if (HashManager.Sha256FromFile(filePath) == file.Hash)
      56. {
      57. Trace.WriteLine(string.Format("Successfully transfered file {0} of {1}", fileIndex + 1,
      58. infos.TotalFiles));
      59. }
      60. else
      61. {
      62. Trace.WriteLine(string.Format("Transfered file {0} does not match the given hash {1}. File-Hash: {2}", fileIndex + 1, file.Hash, HashManager.Sha256FromFile(filePath)));
      63. // File.Delete(filePath);
      64. }
      65. }
      66. Trace.WriteLine("All files transfered! Waiting for client response...");
      67. }
      68. }
      69. catch (Exception ex)
      70. {
      71. Trace.WriteLine("A error occured while transfering the file(s). Message: " + ex.Message);
      72. }

      Sender

      C#-Quellcode

      1. try
      2. {
      3. using (var binaryWriter = new BinaryWriter(tcpClient.GetStream()))
      4. {
      5. var xmlSerializer = new XmlSerializer(transferInfo.GetType());
      6. var serializedClass = string.Empty;
      7. using (var textWriter = new StringWriter())
      8. {
      9. xmlSerializer.Serialize(textWriter, transferInfo);
      10. serializedClass = textWriter.ToString(); // Serialisiere die Klasse und sende sie zum Empfänger
      11. }
      12. binaryWriter.Write(serializedClass);
      13. foreach (var file in fileTransferList)
      14. {
      15. using (var fs = new FileStream(file.FullPath, FileMode.Open, FileAccess.Read))
      16. {
      17. var packets = Convert.ToInt32(Math.Ceiling((decimal) fs.Length/1024)); // 1024 = BufferSize
      18. Debug.WriteLine("Sending " + packets + " packets...");
      19. var remainingBytes = Convert.ToInt32(fs.Length);
      20. for (var i = 0; i < packets - 1; i++)
      21. {
      22. int currentPacketLength;
      23. if (remainingBytes > 1024)
      24. {
      25. currentPacketLength = 1024;
      26. remainingBytes -= currentPacketLength;
      27. }
      28. else
      29. {
      30. currentPacketLength = remainingBytes;
      31. remainingBytes = 0;
      32. }
      33. var sendingBuffer = new byte[currentPacketLength];
      34. fs.Read(sendingBuffer, 0, currentPacketLength);
      35. binaryWriter.Write(sendingBuffer, 0, sendingBuffer.Length);
      36. }
      37. }
      38. Console.WriteLine("File transfered");
      39. }
      40. }
      41. }
      42. catch (Exception ex)
      43. {
      44. MessageBox.Show(@"Failed to transfer all files to the server! Details: " + ex.Message, @"Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
      45. tcpClient.Close();
      46. cmdBrowse.Enabled = true;
      47. cmdTransfer.Enabled = true;
      48. return;
      49. }
      50. MessageBox.Show(@"All files sent!", @"Successful!", MessageBoxButtons.OK, MessageBoxIcon.Information);
      51. tcpClient.Close();


      Bei PNG-Dateien sieht der "Schaden" dann noch schlimmer aus, als bei JPG's.
      Hab wirklich keine Ahnung woran das liegt.
      Bilder
      • beschädigt1.png

        217,53 kB, 619×352, 274 mal angesehen
      • beschädigt2.png

        47,5 kB, 1.165×621, 274 mal angesehen
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      @KaskadekingDE
      Erstmal würde ich nicht den Client überprüfen lassen, ob er sich anmelden konnte. Der Client sollte das Passwort an den Server schicken und der Server schickt dann eine Nachricht zurück, ob der Benutzer sich anmelden konnte oder ob er vielleicht gebannt wurde usw.

      Zu deinem Problem: Hast du mal überprüft, ob die Paketanzahl gleich ist? Sonst würde ich mal versuchen, dass der Client immer auf den Server warten muss, bevor die nächste Datei übertragen wird, also dass du die Dateigröße nicht direkt in dem serialisierten Objekt mitgibst, sondern wie im Beispiel per ReadInt() ausliest. Ich hatte schon mal ein ähnliches Problem, eventuell hilft dir ja auch der Thread hier weiter: Über einen TCP Server gesendete Bytes kommen manchmal nur unvollständig an
      Mfg
      Vincent

      @VincentTB
      Der Client (Sender) überprüft doch gar nicht ob er sich angemeldet hat. Der Server schließt einfach die Verbindung wenn der Client sich nicht angemeldet hat. Das mit der GUID ist auch nur Testweise da. Soll einfach ne Dateiübertragung zwischen 2 PC's sein. Einfach nur so aus Spaß damit ich mich nicht die ganze Zeit langweile ^^

      VincentTB schrieb:

      Hast du mal überprüft, ob die Paketanzahl gleich ist?

      Ja, Client zeigt beim entsprechenden Bild 851 Pakete and und der Server auch.

      VincentTB schrieb:

      Sonst würde ich mal versuchen, dass der Client immer auf den Server warten muss

      Werd ich mal versuchen. Den Thread guck ich mir dann auch mal an :)
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      Ok hab's rausgefunden. Der Client hat 1 Paket zu wenig gesendet weil die for-Schleife falsch war.
      Statt:

      C#-Quellcode

      1. for (var i = 0; i < packets - 1; i++) {
      2. // ...
      3. }

      müsste es so sein:

      C#-Quellcode

      1. for (var i = 0; i <= packets - 1; i++) { }
      2. // oder
      3. for (var i = 0; i < packets; i++)
      KaskadekingDE on GitHub :)
      Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

      Who cares? ¯\_(ツ)_/¯
      Also ich hab das ganze mit dem Serialisieren von Objekten mit einem BinaryFormatter gelöst. Über den Weg könnte man ja auch dann ganze Bilder versenden(Bitmap aus Bild erstellen -> Also Objekt mit BinaryFormatter über NetworkStream per TCPClient an TCPServer schicken, der das ganze mit BinaryFormatter und NetworStream wieder deserialisert und dann wieder in Bitmap konvertiert und abspeichert.

      Versenden:

      C#-Quellcode

      1. System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient();
      2. System.Net.IPAddress ipAddress = System.Net.Dns.GetHostAddresses(Environment.MachineName).Last();
      3. client.Connect(ipAddress, 54321);
      4. using (System.Net.Sockets.NetworkStream ns = client.GetStream())
      5. {
      6. BinaryFormatter bf = new BinaryFormatter(); //System.Runtime.Serialization.Formatters.Binary noch einbinden
      7. bf.Serialize(ns, obj2Send); //object2Send ist das zu Sendende Objekt(Bitmap/whatever)
      8. }


      Empfangen:

      C#-Quellcode

      1. IPAddress ipAddress = Dns.GetHostAddresses(Environment.MachineName).Last();
      2. TcpListener listener = new TcpListener(ipAddress, 54321);
      3. bool running = true;
      4. listener.Start();
      5. while (running)
      6. {
      7. Socket client = listener.AcceptSocket();
      8. using (NetworkStream ns = new NetworkStream(client))
      9. {
      10. BinaryFormatter bf = new BinaryFormatter();
      11. object2Send = (<expliziter typecast>)bf.Deserialize(ns);
      12. ns.Close();
      13. }


      Habs jedenfalls mit einer selbst gemachten Klasse gemacht (binär serialisiert, per Netzwerk versendet und wieder aufgebaut)
      Das einzige Problem, was ich hatte, ist, dass der Empfänger Seite GENAU die selbe Klasse bekannt sein/zur Verfügung stehen muss (Also Klasse public machen und einen Verweis setzen ;D)

      LG Radinator

      Hoffe ich konnte helfen ;D
      In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
      @Radinator
      Bilder musst du gar nicht seralisieren, du kannst sie einfach bitmap.Save(ns, System.Drawing.Imaging.ImageFormat.Jpeg) in den Stream schreiben. Generell empfiehlt es sich, als Serialisierer für Tcp-Verbindungen den NetSerializer zu nehmen: Unglaublich schnell und wenig overhead.

      Meiner Erfahrung nach haben sich Klassenbibliotheken bewährt, in welcher dann alle Klassen drin sind, die benötigt werden. Du hast dann 3 Projekte:
      Skype
      Skype.Server
      Skype.Shared

      Kleiner Tipp noch: Um alles möglichst schnell zu machen, würde ich alle Daten noch mit QuickLZ komprimieren (hier eine gute C# Version)
      Mfg
      Vincent

      Danke @VincentTB!
      Das mit der bitmap war auch nur ein in bsp...hab das mit dem serialisieren allgemein hemeint. Über den weg kann man, falls gebraucht, jede beliebige klasse serialisiern. Mir fällt da zb eine anwendungssynchronisierung ein:
      die einstellungen in einer klasse speichern, per inet verbindung senden und wieder herstellen.

      Aber danke für den tipp mit NetSerializer

      edit:jedenfalls ohne iwelche "3rd party libs" zu verwenden
      In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Radinator“ ()