Protokollentwicklung
-
Die Lösung über den Timer hört sich Interessant an da man noch nen Slider einbauen kann wo man die geschwindigkeit regulieren kann. In einem event darf man ohnehin keine Schleife verwenden. Momentan habe ich das Problem das ich den FileStream global deklariert habe und ihn nicht freigeben kann.
kein Plan wie ich die initialisierung des Filestreams ausserhalb des onRead Events machen soll und ihn wieder freizugeben. Perfekt wäre noch das für jede IP von der Dateien übertragen werden einen expliziten FileStream anzulegen. Ich habe beim Server eine TStringListe wo IP + Dateiname + Dateigröße von jedem Client gespeichert wird.
Eine weitere StringListe speichert die übertragenen bytes und wird pro OnRead entsprechend hochgezählt um zu erkennen wann der File zu ende geladen ist um den Stream wieder freizugeben.Weiß da jemand Rat wie das zu realisieren ist oder bin ich auf dem richtigen Weg

Aber die Sache mit dem globalen Deklarieren und nicht mehr freigeben können nervt total, da muss es doch ne andere Möglichkeit geben wie man explizit für jede Client IP einen Filestream vor dem Senden anlegt und danch wieder freigibt ?
-
Hi Zero01,
Ich hatte mit dem FileStream auch Probleme. Hatte es dann mal mit einem MemoryStream versucht und es hat geklappt.
-
Ok, ich versuche es jetzt auch mal mit dem Memory Stream. Würdest du mir dabei helfen ?
Bis jetzt habe ich folgendes:Global:
TMemoryStream * Stream = new TMemoryStream();Senden
TMemoryStream *mem = new TMemoryStream(); mem->LoadFromFile(Form1->OpenDialog1->FileName); mem->Seek(0,0); Form1->ClientSocket1->Socket->SendStream(mem); delete mem;Empfangen OnReadEvent
int Buffer = 1024; int filesize = StrToInt(FileSize(filelist->Values[Socket->RemoteAddress])); String filename = FileName(filelist->Values[Socket->RemoteAddress]); BYTE *Buffer_BYTEp = new BYTE[Buffer]; Stream->Position = Stream->Size; Socket->ReceiveBuf(Buffer_BYTEp, Buffer); Stream->Write(Buffer_BYTEp, Buffer); delete [] Buffer_BYTEp; if (Stream->Size == filesize) { Stream->SaveToFile(Form2->Label1->Caption + "\\" + filename); delete Stream; }Wie hast du das Empfangen gelöst ? Momentan wird das Programm so übel abgeschossen das man noch nicht mal mehr ne Fehlerausgabe hat

So wie es aussieht steigt er schon beim Senden aus
-
Debuggen und schauen wo genau der Abschuss passiert wär doch mal ne Option?
-junix
-
ich bekomme beim senden eine Acess violation at Address 000000000. Wenn ich das delete auskommentiere tritt dieser Fehler nicht ein, bin total ratlos

-
Hm, wie esch scheint, haben wir wieder einmal das selbe Problem. Anfangs lief bei mir das Progi, also dass heisst einmal, und jetzt habe ich auch diesen Fehler, allerdings nicht immer bei der selben Adresse. Auch wenn ich das delete auskommentiere, tritt dieser Fehler manchmal auf.
-
Man sollte ja auch die mit "new" erstellen Instanzen von Objekten prüfen ob sie denn wirklich erstellt wurden bevor man sie benutzt (o;
-junix
-
ich bin zwar nicht so der borland-freak aber so'n tcp-stack arbeitet immer asynchron. wenn man dem den buffer unterm hintern weglöscht kann's schon crashen. diese borland-klassen haben doch sicher 'ne möglichkeit den status des sockets abzufragen bzw. ob der noch am senden ist etc. erst wenn alles wech ist sollte man die buffer löschen, die datei schliessen usw.
-
Eigentümer des Stream, der als Parameter an SendStream übergeben wird, wird das Windows-Socket-Objekt. Das Windows-Socket-Objekt gibt den Stream nach erfolgter Verarbeitung frei. Versuchen Sie nicht, den Stream, nachdem er als Parameter übergeben wurde, freizugeben.
So, jetzt bekomm ich keine Access Violation mehr beim Senden. Jedoch wird die Datei beim erstellen immer zu groß

Senden
mem = new TMemoryStream(); mem->LoadFromFile(Form1->OpenDialog1->FileName); mem->Seek(0,0); if (mem) Form1->ClientSocket1->Socket->SendStream(mem);Empfangen
int Buffer = 1024; int filesize = StrToInt(FileSize(filelist->Values[Socket->RemoteAddress])); String filename = FileName(filelist->Values[Socket->RemoteAddress]); BYTE *Buffer_BYTEp = new BYTE[Buffer]; Stream->Position = Stream->Size; Socket->ReceiveBuf(Buffer_BYTEp, Buffer); Stream->Write(Buffer_BYTEp, Buffer); delete [] Buffer_BYTEp; if (Stream->Size >= filesize) Stream->SaveToFile(Form2->Label1->Caption + "\\" + filename);Wenn das OnReceive Ereignis einmal ausgelöst wird ist die Datei 1024byte groß und beim zweiten mal 2048..........
Die Quelldatei war aber 1147 bytes groß 
Wie hast du das empfangen gelöst ?
-
Was willst du denn mit dem "if (mem)" da noch?
Ausserdem würde ich nochmal genau überlegen, ob ReceiveBuf() wirklich immer die ganze Buffersize empfängt oder nicht. Als kleiner Tip: Es muss einen Grund geben, wieso ReceiveBuf() das zurückliefert was es zurückliefert (o;
Ansonsten ist das Verhalten aber völlig logisch... Denk nochmal genau darüber nach.
-junix
-
Jaaaaa Junix mein Freund, pro Aufruf subtrahiere ich 1024 byte von filesize solange bis nur noch ein Rest kleiner 1024 bleibt und dies die letzte Puffergröße ist

<= Held vom Erdbeerfeld

-
Heisst das jetzt, dein Problem ist gelöst?
Übrigens: Ich persönlich fänds erheblich eleganter den Rückgabewert von ReceiveBuf() auszuwerten. Es verringert die Dateifehler (o;
-junix
[edit]Ausserdem kümmer dich mal um ordentliche Kommentare und wichtiger: Anständige und aussagekräftige Variablennamen!!![/edit]
-
Das habe ich schon gemacht. Muss zum Fliegerarzt und melde mich später wieder !
-
Ich habe das senden und empfangen so weit hin gekriegt. Zuerst kommuniziert der Client etwas mit dem Server, es wird mitgeteilt, ob Daten gesendent werden sollen, dann die Grösse der Datei und wenn der User dies empfangen möchte, wird dann der Stream gesendet. Ich habe zusätzlich noch ein Form angelegt, welches den Status der Übermittlung anzeiget, Totale Anzahl zusendender Bytes, Anzahl der gesendeten Bytes und einem TCGauge als Frotschrittsanzeige. Das Problem ist jetzt, dass ich ja ein
Application->ProcessMessages();benötige, um das Label mit den empfangenen Bytes zu aktualisieren. Blos wenn ich das drin habe, erhalte die Fehlermeldung: Zugriffsverletzung bei Adresse blablabla. Lesen von Adresse blablabla. lass ich es weg geht alles gut. Wieso?

Hier mal der Code:BytesReceive = Socket->ReceiveBuf(Buffer, BufferSize); //Buffer auslesen Stream->Write(Buffer, BytesReceive); //Buffer in Stream schreiben TotalBytesReceived += BytesReceive; //Anzahl empfangene Bytes aufsummieren Progress->TransferStatus->Progress = TotalBytesReceived; Progress->SendBytesLabel->Caption = TotalBytesReceived; //Application->ProcessMessages(); if(TotalBytesReceived == TotalBytes) { free(Buffer); //Speicherbereich wieder frei geben Progress->Close(); //Statusfenster schliessen Stream->Seek(0, soFromBeginning); //Stream auf Anfang setzten Stream->SaveToFile(SaveDialog1->FileName); //Stream abspeichern Stream -> Clear(); //Speicher freigeben delete Stream; //Stream frei geben delete [] Buffer; //Buffer frei geben FileReadyToReceive = false; FileSizeReadyToReceive = false; FileSizeReceive = false; ServerSocket1->Close(); }
-
Hab deine Variante in ne Testversion eingebaut und muss feststellen das der MemoryStream beim senden sowas von lahm ist. Wird der Stream byte für byte versendet :p ?
ProcessMessages verwendet man in Schleifen, wie es bei events aussieht weiß ich leider noch nicht. Komisch ist das der Empfänger abraucht wenn ich das 2. mal senden möchte. Der erste File Transfer klappt super aber lahm. Bisher hat der Filestream am besten Funktioniert auch wenn er mir 80 -100 % CPU Last für den Process beansprucht.@wedmer: Ich kann ab Sonntag Abend wieder Mitarbeiten wenn ich vom Flugplatz zurück bin. Das bekommen wir schon hin

@Junix: Vielen Dank für deine unermüdliche Hilfe, ich bereite das OnReceive auf und Poste es am Sonntag

-
wedmer schrieb:
[...] free(Buffer); //Speicherbereich wieder frei geben [...] delete [] Buffer; //Buffer frei geben }Was soll das denn werden?
Wenn new [] dann ist free bestimmt nicht gefragt.
Kleiner Tip am Rande. Wenn delete ausgeführt wird, dem Zeiger gleich NULL zuweisen. Das führt dazu, das man doppelte Löschungen besser findet (AV auf Adresse 0 ist eindeutiger zu identifizieren.)
-
Ups,
dass free(Buffer) kam daher, dass ich zuerst den Buffer mit malloc erstellt habe und als ich dann auf new gewechselt habe. Habe jetzt nach jedem delete ein =NULL eigesetzt. Jetzt erhalte ich aber immer noch eine Information, mit dem Inhalt Zugriffsverletzung auf eine Adresse ≠0x00000000 liegt das daran, dass Application->ProcessMessages(); nicht bei Events verwendet werden darf, da es ja eigentlich für Schleifen gedacht ist?@Zero01: habe nun meine MemoryStreams in FileStreams umgewandelt, kann bei mir aber bei der Geschwindigkeit keine Unterschied feststellen.
-
Hat damit gar nichts zu tun. Wo genau passiert denn die AccessVoilation?
Jedenfalls ist das alles jetzt ein Indiz dafür, dass du irgendwo Speicher zerstörst, auf den du in einem späteren Event wieder zugreifen würdest.
-
Wo genau weiss ich auch nicht, er zeigt mir im CPU-Fenster auf den Befehl:
7C91EDDC push ebx
Wo dies im Code genau ist, weiss ich auch nicht. Es muss von mir aus gesehen im OnClientRead-Event sein die Meldung tritt erst ein, nach dem bereits einig Bytes Übertragen wurden.
komisch ist, dass die Meldung nur kommt, wenn ich die ProcessMessages() drin lasse, nehme ich die raus geht alles prima.
-
Scroll mal im CPU-Fenster hoch bis zur nächsten dir bekannten Zeile in C. Alternativ schliesse das CPU-Fenster und du solltest in der IDE die passende Zeile markiert kriegen.
Wenn das auch nichts hilft, dann findest du irgendwo in den Debugfenstern (Ich gluab View-> Debug) den sogenannten "Callstack" oder "Aufrufstack" da wird dir angezeigt in welcher Funktion du grade steckst und wie du da hingelangt bist (aufrufende Funktionen)