Dateiaustausch zwischen clientsocket und serversocket..^^
(kurz vornweg, ja gesucht hab ich schon!)
Hi, wie kann ich eine beliebige Datei zwischen client und Server hin und herschicken? Ich habe mir schon lange gedanken gemacht, aber ich komm einfach nciht auf die Lösung. Die suche hat mir auch nicht viel gebracht, da vieles mit indy erklärt wird. Soweit ich das aber verstanden habe, is das erst ab Delphi 7 verfügbar.. könnt ihr mir weiterhelfen? ich muss doch nur eine atei übertragen... ^^ thx schonmal :) PS: Texte zu verschicken klappt problemlos. Ich weiß auch schon dass ich 'sendstream' nehmen sollte. Aber wie soll ich das mit sendstream verwirklichen? |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Diesen Thread hast Du aber schon gesehen, oder?
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
wo genau ist dein problem? Ein Text ist auch nur eine ansamlung von Bytes. Genau wie eine Datei. Du kannst also eine Datei genau so versenden wie einen Text (vorrausgesetzt ich vermute dein Problem an der richtigen Stelle des Vorhabens). Vielleicht solltest du mal zeigen was du schon hast und wo es genau hängt.
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
also hier meine "produktion" hüstel
ich hab mit type gearbeitet, ich weiß dass man das eig. nicht macht, aber ich hab iwie alles schon ausprobiert, und dann eben auch das.. naja Client onklick
Delphi-Quellcode:
Server onread
type
testrecord=record var screen:TBitmap; begin Varscreen: TBitmap; sendscreen:Testrecord; with sendscreen do begin screen:=Varscreen; end; Clientsocket1.Socket.SendBuf(Varscreen,SizeOf(Sendscreen));
Delphi-Quellcode:
var
receivetext: string; screnVar:TBitmap; incomScreen:testRecord; begin QueryMemo.Lines.Add(DateTimeToStr(Now)+' Uhr: Bild wird geladen'); socket.receivebuf(incomScreen, SizeOf(incomScreen)) ; with incomScreen do begin screnVar:=screen; end; // Image1.Picture.Assign(screnvar); image1.Picture.Bitmap:=screnVar; QueryMemo.Lines.Add(DateTimeToStr(Now)+' Uhr: Bild erhalten'); except showmessage('x'); end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
TBitmap ist eine Klasse und diese sind intern nur Zeiger. Wenn du nun ein TBitmap versendest, dann sendest du nur die Adresse im Speicherbereich deiner Applikation, wo das Objekt liegt. Somit: Keine Daten und nichts. Der Empfänger kann damit nichts anfangen, da an der angegebenen Adresse in seinem Speicherbereich was ganz anderes liegt.
Vorschlag: schau dir mal in der Hilfe folgendes an und ich denke mal, du kommst auf die Idee, welche ich dir hier schmackhaft machen will: TMemoryStream, TBitmap.SaveToStream, TCustomWinSocket.SendStream |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
also dann sowas in der art oder wie?
(hier jetzt einfach mal am beispiel von einem Screenshot, den muss man nicht aus ner datei laden) Client
Delphi-Quellcode:
Server
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket); var Stream : TMemoryStream; begin Stream := TMemoryStream.Create; clientsocket1.Socket.ReceiveBuf(stream,sizeof(stream)); image1.Picture.Bitmap.LoadFromStream(stream); end; procedure TForm1.Button1Click(Sender: TObject); begin ClientSocket1.Port := 270; //Festlegung des Ports ClientSocket1.Host := '127.0.0.1'; //IP des Zielrechners ClientSocket1.active := true; //Aufbau der Verbindung end;
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin ServerSocket1.Port := 270; //Festlegung des Ports ServerSocket1.active := true; //Aktivierung der ServerSocket end; {procedure MakeScreenShot(const ATarget: TBitmap); var DesktopDC: HDC; begin DesktopDC := CreateDC('DISPLAY', nil, nil, nil); try ATarget.PixelFormat := pfDevice; ATarget.Width := Screen.Width; ATarget.Height := Screen.Height; BitBlt(ATarget.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DesktopDC, 0, 0, SRCCOPY); finally DeleteDC(DesktopDC); end; end;} <--irrelevant procedure TForm1.Button1Click(Sender: TObject); var Stream : TMemoryStream; bitmap:Tbitmap; begin Stream := TMemoryStream.Create; MakeScreenShot(bitmap); bitmap.SaveToStream(Stream); Stream.Position := 0; Stream.Free; Serversocket1.Socket.Connections[0].SendStream(Stream); end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Zitat:
Delphi-Quellcode:
Das wird zu Problemen führen, weil die OnClientRead() Funktion mehrfach aufgerufen wird (werden kann), bis du die gesamten Daten empfangen hast. Somit musst du den Memorystream woanders erzeugen (so das du wirklich nur eine Instanz davon hast) und damit du mit jedem OnClientRead die neu empfangenen Teile direkt hinten an den MemoryStream anhängen kannst. Wenn du dann alle Daten empfangen hast, dann kannst du aus dem MemoryStream die Daten auslesen.
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket); var Stream : TMemoryStream; begin Stream := TMemoryStream.Create; clientsocket1.Socket.ReceiveBuf(stream,sizeof(stream)); image1.Picture.Bitmap.LoadFromStream(stream); end; Folgende Fehler in deiner Routine: 1. Du erzeugst jedes mal eine neue Instanz von TMemoryStream - du brauchst nur eine 2. Du gibst die Instanz bei ReceiveBuf() an, aber der will einen Zwischenpuffer haben. Du kannst die Instanz niemals bei dieser Funktion direkt angeben. 3. Instanzen sind intern nur Zeiger auf das Objekt im Speicher - siehe mein Beitrag zuvor. Was für das Senden gilt, gilt hier genauso für das Empfangen, schliesslich sind es jedesmal Instanzen. 4. Nach dem Schreiben von Daten in den Stream, wird der Dateizeiger (TStream.Position) auch um die jeweilige Byteanzahl weiter gesetzt und LoadFromStream() liest aber der aktuellen Dateiposition. Damit würde LoadFromStream() immer fehlschlagen, da er immer am Ende der Daten steht. 5. Du gibst nirgendwo den Stream wieder frei.
Delphi-Quellcode:
1. Wenn du den Stream mit .Free wieder freigibst (und er somit weg ist), was soll er denn bei dem Aufruf danach noch versenden? Datenmüll? Naja, das macht er bestenfalls sogar.
procedure TForm1.Button1Click(Sender: TObject);
var Stream : TMemoryStream; bitmap:Tbitmap; begin Stream := TMemoryStream.Create; MakeScreenShot(bitmap); bitmap.SaveToStream(Stream); Stream.Position := 0; Stream.Free; Serversocket1.Socket.Connections[0].SendStream(Stream); end; 2. Den Stream grundsätzlich nicht freigeben, weil SendStream() übernimmt diesen Part für dich (siehe TCustomWinSocket.SendStream(), da nur SendStream weiss, wann er alles gesendet hat. SendStream macht dies im Hintergrund. 3. Du gibst nirgendwo das Bitmap wieder frei. Am besten mal die Senderoutine aufräumen, da biste wohl am schnellsten bei einer funktionierenden Lösung... |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
okay...^^
also erstmal echtn riesen Dank, dass du dir so viel Mühe gibst, mir das zu erklären! :cheers: (bestimmt nicht leicht xD) Ich versteh auch fast alles. Erstmal zum Server: stimmt das jetzt so (hoff mal schon, denk aber eher nicht^^)
Delphi-Quellcode:
und zum Client nochmal: Dass ichs nicht im onread schreiben darf, leuchtet mir ein, logo! kann nicht klappen. Aber wo soll ich anders (wenn nicht im on read) programmieren, dass das Programm den Stream läd, wenn er doch nicht weiß, wann der stream kommt? (ich hoffe du verstehst was ich meine^^) Und ansonsten sind alle Fehler die ich beim Client gemacht habe durchaus logisch zu verstehen, ich weiß jetzt dass es Fehler sind, und warum, aber ich wüsste nicht, wie ich es anders machen soll (außer Punkt 5^^)
procedure TForm1.Button1Click(Sender: TObject);
var Stream : TMemoryStream; bitmap:Tbitmap; begin Stream := TMemoryStream.Create; MakeScreenShot(bitmap); bitmap.SaveToStream(Stream); Stream.Position := 0; Serversocket1.Socket.Connections[0].SendStream(Stream); bitmap.Free; end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Zitat:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var Stream: TMemoryStream; bitmap: TBitmap; begin Stream := TMemoryStream.Create; MakeScreenShot(bitmap); try bitmap.SaveToStream(Stream); finally bitmap.Free; end; Stream.Position := 0; Serversocket1.Socket.Connections[0].SendStream(Stream); end; Zitat:
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
okay.. also das mit dem "außerhalb von Onread" erstellen müsste dann so gehen oder wie?
Delphi-Quellcode:
und im On read soll dann das stehen?
FStream := TFileStream.Create('c:\temp\test.stream.bmp', fmCreate or fmShareDenyWrite);
end;
Delphi-Quellcode:
das habe ich ich jetzt außerhalb von DP gefunden
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket); var iLen: Integer; Bfr: Pointer; begin iLen := Socket.ReceiveLength; GetMem(Bfr, iLen); try Socket.ReceiveBuf(Bfr^, iLen); FStream.Write(Bfr^, iLen); finally FreeMem(Bfr); end; end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Joa, zum Beispiel. Das kannst du ja auch leicht abändern um statt einem FileStream ein TMemoryStream zu nutzen, wenn du keine Datei erstellen willst sondern das Bild nur anzeigen willst.
Fehlt nur noch das Problem: wann hast du das Bild komplett empfangen und kannst das Bild aus dem Stream lesen und diesen freigeben? |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
also ich habs jetzt eingefügt und er startet auch ohne Probleme und connected auch ohne Probleme. Wenn ich beim Server per button einen screenshot machen will und ihn zu schicken, dann kommt dieser Fehler:
Zitat:
Server:
Delphi-Quellcode:
//edit: um herauszufinden wie lang der stream ist: würde doch so gehen oder?:
procedure TForm1.Button1Click(Sender: TObject);
var Stream : TMemoryStream; bitmap:Tbitmap; begin Stream := TMemoryStream.Create; MakeScreenShot(bitmap); //Fehlermeldung! Wundert mich, der Code war aus ner Codelibrary O:-) bitmap.SaveToStream(Stream); //Fehlermeldung! Stream.Position := 0; Serversocket1.Socket.Connections[0].SendStream(Stream); bitmap.Free; //Fehlermeldung! end; sizeof(stream) // der Vollständigkeit halber hier nochmal der abgeänderte Clienttext:
Delphi-Quellcode:
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket); var Stream : TFileStream; begin Stream := TFileStream.Create('c:\teststream.bmp', fmCreate or fmShareDenyWrite); clientsocket1.Socket.ReceiveBuf(stream,sizeof(stream)); image1.Picture.Bitmap.LoadFromStream(stream); end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Delphi-Quellcode:
das Create vergessen :)
procedure TForm1.Button1Click(Sender: TObject);
var Stream : TMemoryStream; bitmap:Tbitmap; begin Stream := TMemoryStream.Create; bitmap:=TBitmap.create //!! MakeScreenShot(bitmap); //Fehlermeldung! Wundert mich, der Code war aus ner Codelibrary O:-) bitmap.SaveToStream(Stream); //Fehlermeldung! Stream.Position := 0; Serversocket1.Socket.Connections[0].SendStream(Stream); bitmap.Free; //Fehlermeldung! end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Zitat:
jo okay...jetzt hab ich zwei fehlermeldungen. der CLient kann den stream nicht in den Pfad speichern und schon wieder eine Zugriffverletzung.
Delphi-Quellcode:
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket); var Stream : TFileStream; begin Stream := TFileStream.Create('c:\teststream.bmp', fmCreate or fmShareDenyWrite); //hier der Fehler! clientsocket1.Socket.ReceiveBuf(stream,sizeof(stream)); image1.Picture.Bitmap.LoadFromStream(stream); end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Zitat:
Zitat:
Zitat:
SizeOf() genauso wenig, weil damit kannst du sogar noch eher erkennen das es nicht geht: Lass dir mal das Ergebnis von SizeOf() ausgeben: es ist immer 4, also 4 Bytes. Somit kann dies nicht sein! |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
ja okay hab ich vergessen zu ändern. Liegt aber auch vielleicht daran, dass ich nicht weiß, wie ich es besser machen soll.
Receivestream gibt es nicht beim Clientsocket, für receive gibt es nur den buf! Ich weiß jetzt dass es falsch ist, aber wie es richtig gehen soll, weiß ich auch nicht.. ich arbeite noch nciht so lange mit Delphi also bitte erwartet nicht zuviel Ich versuch ja alles zu verstehen, und verstehs ja auch, aber was bringt es mir, wenn ich den Fehler kenne, aber kA hab wie ich ihn lösen soll? (außer dass ich ihn nicht nochmal mache, aber auch dafür muss ich es richtig wissen) wär also ganz nett, wenn du mir eine Hilfe geben würdest, oder (was es uns beiden leichter machen würde, und dir viele nerven erspart ( :-D ) wenn du mir den Fehler verbesserst und deine Verbesserung begründest. Daraus kann ich am meisten lernen (falls es dir darauf ankommt) ;) schonmal thx für die antwort^^ lg cRayZo //edit: was mir grad auffällt: wens dutzen stört, der sagts bitte^^// |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Es gibt kein ReceiveStream, weil der Socket nicht weiss, wie lang ist denn der Stream. Er weiss nicht wieviele Daten er in den Stream reinschreiben soll und wann halt Schluss ist. Er selber ist reiner Datenüberträger. Alles was du ihm gibst, schickt er so unverändert über den Socket raus. Wenn du SendStream() aufrufst, dann schreibt er einfach alle Daten aus dem Stream in den Socket bis der Stream zu Ende ist. Aber: als Empfänger weiss er nicht was für Daten da ankommen, woher und wie lang. (Als Sender interessiert ihn das auch herzlich wenig). Langer Rede, kurzer Sinn: es gibt kein ReceiveBuf(), weil die Socket Komponenten das gleiche Problem beim empfangen haben wie du: wann fängt der Stream an und wie lang ist er? Wann ist der Stream fertig? Der Socket könnte natürlich vor dem Stream die Grösse des selbigen übertragen, aber das macht er nicht, weil er damit sonst eine Art Protokoll definieren würde - und das macht er nicht. Er soll nur rein Daten übermitteln und sich darin keine Ordnung festlegen. Das ist nun deine Aufgabe.
Und zu deinem Problem mit dem ReceiveBuf: ReceiveBuf() will einen Buffer sehen, in den er die Daten reinschreiben kann. Danach kannst du den Buffer in deinen Stream schreiben. Ich habe dir die gesamte Zeit keinen Quelltext dazu gegeben sondern nur die Fehler aufgezeigt, da du selber eine passende Routine zum empfangen mit Puffer schon gepostet hast: hier. Damit hast du das eine Problem schonmal gelöst: Daten empfangen und in einen Puffer bekommen und danach weiter in den Stream. Das einzige was noch fehlt: wann den Stream anlegen und wann hast du ihn komplett empfangen so dass du das Bild aus dem Stream laden kannst? Irgendwelche Ideen? |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
der sender (hier der server) könnte, nachdem er alle Daten gesendet hat, eine msg schicken, dass er fertig gesendet hat.
und wenn du mich jetzt nicht vollständig durcheinandergebracht hast, sollte das dann so aussehen?
Delphi-Quellcode:
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket); var iLen: Integer; Bfr: Pointer; Stream : TFileStream; begin iLen := Socket.ReceiveLength; GetMem(Bfr, iLen); try Socket.ReceiveBuf(Bfr^, iLen); FStream := TFileStream.Create('c:\teststream.bmp', fmCreate or fmShareDenyWrite); //edit: der müsste außerhalb von onread erstellt werden oder verwechsel ich jetzt wieder was? FStream.Write(Bfr^, iLen); //hier die msg, dass Bild da ist isowas wie if receivetext=bla then image1.Picture.Bitmap.LoadFromStream(Fstream); finally FreeMem(Bfr); end; end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Deine Kommentare sind richtig: Create des Streams ausserhalb von OnRead und das anzeigen, wenn er fertig is.
Aber zu deiner Idee mit der Message: Was ist - egal wie die Message nun im Endeffekt aussieht - wenn genau diese Bytefolge in dem übertragenen Bild enthalten ist? Dann bricht er zu früh ab und versucht ein unvollständiges Bild zu laden. Wäre nicht die Übermittlung der Grösse der Bilddaten vor diesen sinnvoller? Ein anderes Problem: ReceiveText weisst nicht ob die Daten im Socket Text oder andere Daten sind. Wenn du noch nicht fertig alles empfangen hast, dann würdest du mit ReceiveText sogar die Daten als string bekommen... |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
also kann ich im server, wenn ich das Bild komplett geladen habe (sprich nach dem screenshot) einen sizeof machen? das müsste doch noch gehen oder?
was anderes könnte ich mir nicht vorstellen, bzw wüsste es nciht besser |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Nein, nimm nicht SizeOf, da kommt sowieso immer vier raus. Nimm Stream.Size.
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
okay
Delphi-Quellcode:
wenn ich die Länge vorher aber in einem Sendtext übertrage, gehts ja nicht, weil
var size:integer;
(...etc) bitmap.SaveToStream(Stream); size:=stream.Size; (senden...etc) Zitat:
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Du sendest auf Serverseite erstmal die Größe mit SendBuf und dann den eigentlichen Stream mit SendStream. Auf der Clientseite prüfst du, ob die Übertragung schon begonnen hat - wenn nein, dann liest du die Größe und speicherst sie global. Andernfalls liest du mit deiner eigenen Methode (Puffer allozieren, lesen und in den Stream speichern) die Daten aus und prüfst, ob du die Gesamtgröße schon erreicht hast.
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Hallo,
ich habe das Gefühl das hier mit "nicht blockierenden Socktes" gearbeitet wird. Ich empfehle Dir die Komponenten in den "blockierenden Modus" zu schalten und die Übertragung mit TWinSocketStream zu realisieren. Dann lösen sich alle hier genannten Probleme in Luft auf. Die speicherst alles was Du Üertragen möchtest in einen Stream der dann mit TWinSocketStream gesendet wird. Das Bitmap könntest Du dann mit TBitmap.SaveToStream(aWinSocketStream) senden. Für die serverseitige ClientExecute Methode gibt es sogar ein Beispiel in der OH. |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Zitat:
Stream.Size ist schon die richtige Antwort von Apollonius. Und zu deinem Problem mit dem SendText: Sende die Grösse einfach nicht in Textform (also als String) sondern als Binäre Daten. Dann ersparst du dir einfach das Umwandeln in den String und zurück und vor allem: du hast eine definierte Länge. Die Grösse eines LongInt/Int64/Char/Byte etc sind immer gleich gross bei dem gleichen Compiler und Zielsystem, weil sonst könnte der Compiler schlecht beim Erstellen des Programmes den Speicherplatz für Variablen vorhalten. Von daher wäre das eine gute Lösung. Soviel zur Theorie, nun zum Code: Die Grösse dieser Variablen bzw. des Typs ermittelst du - tada - mit SizeOf(). Dieses würde dir z.B. für LongInt 4 Bytes liefern und für Int64 sogar 8 Bytes. Damit hättest du die Gewissheit, dass du immer nur (bei Nutzung eines LongInt's) 4 Bytes vorne die Grösse sind und alles nachfolgende schon die Stream-Daten.
Delphi-Quellcode:
Auf der Gegenseite einfach die Länge auslesen und dann damit arbeiten. Und damit du z.B. unterscheiden kannst, ob du nun das erste Mal versuchst Daten zu lesen und somit erstmal die 4 Bytes Streamgrösse auslesen musst oder ob es schon Stream-Daten sind, kannst du dich ja an deinem Empfangsstream orientieren: ist er schon angelegt, dann weisst du um die Länge, wenn nicht, dann erstmal diese auslesen...
var
lLen: LongInt; begin ... // Bitmap sichern in Stream, etc ... lLen := Stream.Size Socket.SendBuf(lLen, SizeOf(lLen)); Socket.SendStream(Stream); end; Und das mit dem Empfangen der Länge solltest du mit dem Codeschnipsel gut selbst hinbekommen. @other: Ja, ich hätte auch alles einfach mit Integer erklären können, aber ich bezog mich darauf, dass die Datentypen bei den gleichen Compilern und Zielsystemen gleich gross sind. Leider wächst aber Integer (generischer Ganzzahl-Typ) mit und wird bei einem 64-Bit Compiler (Delphi "Commodore", Winter 2008) auch 64 Bit gross sein, von daher wollte ich diesen Fakt nicht auswälzen und habe LongInt genommen, weil das definitiv 32 Bit gross bleibt. |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
okay, wieder scheiterts am Vokabular
ich hab mir versucht irgendwie trotzdem zu helfen :lol: (trau mich ja fast ned das zu posten :? ) hier für den empfänger (Client)
Delphi-Quellcode:
kanns Programm übrigens ohne Fehler starten, aber beim sendeversuch kommt ein Fehler.. (iwie auch klar)
begin
iLen := Socket.ReceiveLength; GetMem(Bfr, iLen); try Socket.ReceiveBuf(Bfr^, iLen); FStream.Write(Bfr^, iLen); if FileExists('c:\teststream.bmp') then begin if x=Fstream.Size then image1.Picture.Bitmap.LoadFromStream(Fstream)end else begin x:=strtoint(copy(inttostr(Socket.ReceiveBuf(Bfr^, iLen)),0,4)); // * weiter unten --> FStream := TFileStream.Create('c:\teststream.bmp', fmCreate or fmShareDenyWrite); end; finally FreeMem(Bfr); end; //*bestimmt viel leichter^^ aber ich kenn nur copy und copy geht nunmal soweit ich weiß nur mit string^^ end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Ok, dann doch mal der Code beim Client:
1. Eine Variable vom Typ TStream im private Abschnitt der Form deklarieren (für die Daten) und dazu eine Variable vom Typ Integer, welche die Grösse der Daten hält.
Delphi-Quellcode:
2. Empfangsroutine: OnClientRead
xxx = class(TForm)
... private FStream: TStream; fStreamDataSize: Integer; ... end;
Delphi-Quellcode:
3. Beim Server folgendes um die Grösse vorne weg zu senden:
procedure xxx.ClientSocket1ClientRead(...)
var iLen: Integer; Bfr: Pointer; begin if not assigned(FStream) then // noch keine Übertragung bisher, Stream ist nil begin // Ok, dann müssten wir erstmal schauen und die Grösse des folgenden Streams // auslesen. Dazu erstmal schauen, ob wir die Grösse bisher überhaupt komplett empfangen haben... if Socket.ReceiveLength >= SizeOf(fStreamDataSize) then begin // dann nun die Grösse einlesen Socket.ReceiveBuf(fStreamDataSize, SizeOf(fStreamDataSize)); // dann Stream anlegen FStream := TMemoryStream.Create; end; // else // Exit; // ok, dann weiter warten, bis wir die Grösse komplett empfangen haben (Code unnötig) end; // ok, hier nun, wenn der Stream existiert, einlesen der Daten die empfangen wurden und Schreiben in den Stream if assigned(FStream) then begin iLen := Socket.ReceiveLength; // Ok, nur die Daten auch empfangen, die zu unserem Stream gehören. Also schauen wieviel wir noch vom Stream einlesen // müssen... iLen := Min(fStreamDataSize, iLen); GetMem(Bfr, iLen); try Socket.ReceiveBuf(Bfr^, iLen); // fStreamDataSize := fStreamDataSize - FStream.Write(Bfr^, iLen); // beides gleich - schreiben der Daten Dec(fStreamDataSize, FStream.Write(Bfr^, iLen); // und Variable fStreamDataSize runterzählen um die // empfangenen und geschriebenen Daten... finally FreeMem(Bfr); end; if fStreamDataSize = 0 then // alles empfangen? begin // Positionszeiger zurücksetzen FStream.Position := 0; // Image einlesen Image1.Picture.Bitmap.LoadFromStream(FStream); // MemoryStream freigeben und auf nil setzen (wegen den If Assigned() Abfragen) FreeAndNil(FStream); end; end; // wenn er hier ankommt und ReceiveLength() ist immernoch > 0, dann sind noch Daten im Stream, die aber nicht // mehr zum Bild gehören - oder - wir haben die Grösse der Streamdaten noch nicht empfangen. end;
Delphi-Quellcode:
So, soweit zur Theorie. Alles hier im Forumfenster geschrieben, sollte aber so laufen...
var
lLen: Integer; lStream: TStream; begin lStream := TFileStream.Create('c:\testbild.bmp', fmOpenRead); lLen := lStream.Size; // grösse Stream ermitteln Socket.SendBuf(lLen, SizeOf(lLen)); // Grösse senden Socket.SendStream(lStream); // dann das Bild hinten dran... end; |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
jo ist gebongt und jetzt?.. :?:
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Zitat:
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
achso, kein Problem, ja vielen Dank auf jeden fall!!!
einmal nur ne klammer vergessen(is ja np ;) ) mein delphi gibt den Ausdruck 'min' nur als nicht definiert zurück.
Delphi-Quellcode:
das versteh ich aber nicht, ist doch eine Funktion
iLen := Min(fStreamDataSize, iLen);
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Jo, und definiert in der Unit Math.pas. Somit die UsesListe um Math erweitern oder selbst schnell eine If Abfrage schreiben...
/EDIT: Ich habe die erste IF Abfrage nochmal auf >= geändert. > muss nicht sein, >= reicht schliesslich schon... Und wo habe ich eine Klammer vergessen? |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
okay, das klappt schonmal ;) thx
beim sendeversuch kommt allerdings noch (nach 4 sekunden warten, nach dem buttonklick) ein access violation im Clientprojekt und dieses CPU Fenster öffnet sich. hat da jemand eine idee??:( //edit: die klammer hattest du bei
Delphi-Quellcode:
vergessen, als ich den text kopiert hatte. Jetzt ist sie ja da, gut^^
Socket.ReceiveBuf(fStreamDataSize, SizeOf(fStreamDataSize));
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Unit math
...zu spät ;) |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
okay also ich hab den access violation-Fehler mal weiter verfolgt.
er tritt nicht auf, wenn ich das Bitmap im Client nicht vom Stream lade sprich wenn ich folgendes aus dem Code herausnehme:
Delphi-Quellcode:
also hat der scheinbar ein Problem mit dem laden des Streams würd ich mal sagen, aber was, weiß ich jetzt nicht, habt ihr da eine Idee?
// Image einlesen
Image1.Picture.Bitmap.LoadFromStream(FStream); |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Naja, gibt es denn auch ein Image1 auf deiner Form?
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
natürlich, ansonsten würde ja schon vor dem Start ein Fehler kommen und das Prog. würde erst gar nicht starten.
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Zitat:
|
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Fehler der Klasse EInvalidGraphic
Meldung: Bitmap ist ungültig´ //edit: hab auch nochmal gesucht, aber sowas hilft mir da auch jetzt nicht wirklich. |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
Wenn das Bitmap wirklich ungültig sein sollte (was eine ganz andere Exception ist als eine Access Violation(!!)), dann kann folgendes sein:
1. Das Bild wird falsch beim Sender in den Stream gespeichert (welcher später versendet wird) 2. Das Bild ist einfach kein Bitmap 3. Das Bild wird zu früh geladen 4. Es werden noch andere Daten dazwischen gesendet (wie man dies auch immer hinbekommen sollte) Aber um das mal zu untersuchen, wäre es zu empfehlen sich die empfangenen Daten anzuschauen. Also speicher mal den MemoryStream vor dem Anzeigen in dem Image (SaveToFile()) und dann schau mal, ob die Datei vom Inhalt die gleiche ist wie die gesendete... |
Re: Dateiaustausch zwischen clientsocket und serversocket..^
sorry, mein Fehler, bin selber drauf gekommen. Beim Server hab ich etwas mit reinkopiert, was schon drinstand. Ich hab die Länge zweimal gesendet, somit war im ankommenden stream nach der rausgefilterten Größe noch immer die Größe am Anfang, welche der stream natürlich nicht ins Bild laden konnte. Es klappt jetzt, nochmal VIELEN DANK!! :mrgreen:
PS: vll nurnoch eine kleine Frage: wie kann man ein Bild von der Größe verkleinern? also halbieren, dritteln..? Antwort muss nicht sein wär aber noch der Punkt auf dem i ;) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:27 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz