Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Übertragungsprotokoll für TSocket ??? (https://www.delphipraxis.net/148631-uebertragungsprotokoll-fuer-tsocket.html)

jokerfacehro 5. Mär 2010 12:07


Übertragungsprotokoll für TSocket ???
 
Hallo,

ich habe ein Client-Server-System basierend auf dem TSocket per TCP erstellt.

Delphi-Quellcode:
Socket(AF_INET,
                   SOCK_STREAM,
                   IPProto_TCP);

das problem ist, das alt bekannte.
wie schaffe ich es die daten richtig zu verpacken, sodass der empfänger damit ordentlic harbeiten kann.


ich habe mir ein protokoll ausgedacht, das folgendermaßen aussieht:
(die begriffe Frame und Packet sind nicht auf das OSI modell bezogen)


jeder Frame hat 8192 bytes

zuerst kommt ein header Frame:
er besteht aus
- GlobalID (2Byte) diese beschreibt das Paket, zu welchem mehrere Teile gehören, bei jedem Teilstück ist diese ID gleich
- LocalID (2Byte) diese identifiziert das Teilstück an sich.
- Command (2Byte) ist das auszuführende kommando
- Daten (8186Byte) die ersten teile der daten


dann folgen die Daten Frames:
-GlobalID (2Byte)
-LocalID (2Byte) diese wird bei jedem Frame inkrementiert
-Daten (8188Byte)


der letzte Frame hat die LocalID 1111 1111 1111 1111 (0xFFFF) (erstmal vernachlässigbar für das folgende beispiel)
wodurch das ende des paketes angegeben wird.



so sieht ein beispiel aus wie ich die daten sende:

Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var st:TFileStream;
    str:string;
    buffer:array[1..8192] of Byte;
begin

st:=TFileStream.Create('C:\Dokumente und Einstellungen\Admin\Eigene Dateien\server\1670478.jpg',fmOpenRead);
st.Position:=0;


str:=#00#01#00#01#00#04+IntToStr(st.Size)+#13#10+'C:\'+#13#10+'pic.jpg'+#13#10; //frameheader und erste daten


Send(FConnectSocket[0],str[1],Length(str),0);
buffer[4]:=$00000;
while st.Position<st.Size do begin
//FillChar(buffer,8192,#0);
buffer[1]:=$0000;
buffer[2]:=$0001;
buffer[3]:=$0000;
buffer[4]:=buffer[4]+$0001;
st.Read(buffer[5],8188);
Send(FConnectSocket[0],buffer[1],Length(buffer),0);
end;
  st.Free;

end;

das funktioniert allerdings nicht ganz.
der server scheint alles richtig zu senden, zumindest steht alles richtig in buffer drin

das problem ist jetzt folgendes:

beim Client kommt der Header Frame richtig an und wird auch korrekt verarbeitet.
ich empfange immer genau 8192 Bytes;

jeder weitere Datenteil der ankommt, hat auch den header dran und wird zum paket hinzugefügt.

allerdings variiert die komplette datengröße
das bild ist 650KB groß und es kommen mal 140KB an, mal 300, mal 640.



so empfange ich per WndProc:
Delphi-Quellcode:
var buffer:string;

FD_READ:
      begin

      setLength(buffer,8192);

        count:=recv(wp,buffer[1],8192,0);
        {setLength(buffer,count);

        packeter(buffer);}

        while count>0 do begin
        setLength(buffer,count);
        packeter(buffer);
        setLength(buffer,8192);
        count:=recv(wp,buffer[1],8192,0);
        end;

        writeln(IntToStr(Length(Packets[0].Data)));

        //writeLn(ntohs(socketaddr.sin_port));
        //OnRead(wp,buffer);
        PostQuitmessage(Msg);
        //-- WMOnAsyncServerData(wp, lp);
     end;



aber nicht das richtige.

was mache ich falsch ?

SirThornberry 5. Mär 2010 12:26

Re: Übertragungsprotokoll für TSocket ???
 
Welche Delphiversion hat du denn?

jokerfacehro 5. Mär 2010 12:26

Re: Übertragungsprotokoll für TSocket ???
 
ich nutze Delphi 7 Enterprise

Sherlock 5. Mär 2010 12:29

Re: Übertragungsprotokoll für TSocket ???
 
zur Erinnerung: Das ganze NonVCL!

Sherlock

jokerfacehro 5. Mär 2010 12:35

Re: Übertragungsprotokoll für TSocket ???
 
ja das ganze soll auf der client seite nonVCL sein.
der server kann VCL nutzen.

deswegen will ich auf der Client seite auch keine Streams nutzen.

hab hier mal reingeschaut, ist allerdings sehr unübersichtlich.
http://www.delphi-library.de/viewtop...er=asc&start=0


und ich hab ma nen chat auf string basis mit terminator geeschrieben.

allerdings will ich jetzt daten und befehle, also teilweise Bytes teilweise strings übertragen und
für Dateiübertragung brauche ich ja ein anderes verfahren, deshalb diese Variante,
fallsihr eine bessere möglichkeit habt das mit TSocket zu realisieren, könnt ihr die gern an bringen.

auf jedenfall soll das ganze nonVCL sein und TSocket nutzen.

sirius 5. Mär 2010 12:38

Re: Übertragungsprotokoll für TSocket ???
 
Du musst die Pakete unterschiedlicher Größe sammeln und dann immer schauen, ob eins deiner Frames fertig ist. Das ist dir bewusst (kam jetzt nicht so heraus)?

jokerfacehro 5. Mär 2010 12:41

Re: Übertragungsprotokoll für TSocket ???
 
ähm

kannn sein, dass ich dich falsch verstanden habe, sirius.

also in paketer wird der buffer ausgewertet:

Delphi-Quellcode:
type TPacket = record
      GlobalID:Word;
      LocalID:Word;
      CMD:Word;
      Data:string;
      end;


procedure packeter(buffer:string);
var check:boolean;
    i:integer;
begin
if Copy(buffer,3,2)=#0#1 then begin
        setLength(Packets,Length(Packets)+1);

        Packets[Length(Packets)-1].GlobalID:=Byte(buffer[1])+Byte(buffer[2]);
        Packets[Length(Packets)-1].LocalID:=Byte(buffer[3])+Byte(buffer[4]);
        Packets[Length(Packets)-1].CMD:=Byte(buffer[5])+Byte(buffer[6]);
        Delete(buffer,1,6);
        Packets[Length(Packets)-1].Data:=buffer;

        end
        else begin
        {check:=false;
        for i:=0 to Length(Packets)-1 do
          if Packets[i].GlobalID=Byte(buffer[1])+Byte(buffer[2])then begin
            check:=true;
            break;
          end;
        Delete(buffer,1,4);
        if check then}
           Delete(buffer,1,4);
          Packets[0].Data:=Packets[0].Data+buffer;
        end;

end;
Das ist alles hier grad erst mal testweise hingeschrieben, deswegn auch Packets[0] ganz unten,
da ich eh erstmal nur ein Packet übertrage, nämlich das fürs bild

sirius 5. Mär 2010 13:01

Re: Übertragungsprotokoll für TSocket ???
 
Ja, aber das Socket zerschneidet dir doch deine Pakete. TCP achtet nur darauf, dass Sie in der richtigen Reihenfolge ankommen.
Was ist, wenn gerade an der Stelle gebrochen wird, wo auch das Bild mit #0#1 weitergeht?

Du musst den gesamtn Datenstrom erstmal sammeln:
Delphi-Quellcode:
setlength(tempbuffer,8192);
len:=recv(s,tempbuffer[1],length(tempbuffer),0);
setlength(tempbuffer,len);
buffer:=buffer+tempbuffer;

//analysiere buffer auf fertiges Paket
//wenn Paket fertig, bearbeite Paket und lösche so viele Bytes von buffer-Anfang, iwe Paket groß war

jokerfacehro 5. Mär 2010 13:20

Re: Übertragungsprotokoll für TSocket ???
 
so

ich habs mal so gemacht und mir die länge ausgeben lassen:

Edit: jede zeile steht für eine FM_READ MSG die abgearbeitet wurde.
insgesamt sind trotzdem nicht alle daten angekommen.

:wall: :mrgreen:


28
8192
16384
8192
0
024576
49152
0
0
32768
65536
8192
0
0
163840
0
0
196608
0
0
0
0


ich versteh nicht warum er nicht gleich alle daten einliest, sondern in unterschiedlichen abständen
ne neue MSG macht :gruebel:

jokerfacehro 5. Mär 2010 13:49

Re: Übertragungsprotokoll für TSocket ???
 
ich verstehs einfach nicht.

die anzahl der insgesamt empfangenen daten variiert ständig bis zu 100kb.

wie kann sowas zustande kommen ???

lese ich den FileStream falsch ein ???

Astat 5. Mär 2010 14:13

Re: Übertragungsprotokoll für TSocket ???
 
Zitat:

Zitat von jokerfacehro
ich verstehs einfach nicht.

Thread #15 mit Kugeln:

http://www.delphipraxis.net/internal...623&highlight=

lg. Astat

jokerfacehro 5. Mär 2010 14:15

Re: Übertragungsprotokoll für TSocket ???
 
sooooooooooooooooooooooooooooooooooooooooooooooooo oooooooooooooooooooooooooooooooooooooooooo

problem erkannt, allerdings noch keine lösung gefunden es zu beheben:

ich habs jetzt hinbekommen, es lag am sender:

Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var st:TFileStream;
    str:string;
    buffer:array[1..8192] of Byte;
    i:integer;
begin

st:=TFileStream.Create('C:\Dokumente und Einstellungen\Admin\Eigene Dateien\data\backer\server\txt.txt',fmOpenRead);
st.Position:=0;
i:=8192;

//FillChar(str,8192,#0);
//str:=#00#01#00#01#00#04+IntToStr(st.Size)+#13#10+'C:\'+#13#10+'txt.txt'+#13#10;
//Send(FConnectSocket[0],str[1],Length(str),0);
setLength(str,i);
while st.Position<st.Size do begin
//FillChar(buffer,1024,#0);
if st.Size-st.Position<8192 then begin ///----> wichtig
 i:=st.Size-st.Position;
 setLength(str,i);
 end;
st.Read(str[1],i);
Send(FConnectSocket[0],str[1],Length(str),0);
end;
  st.Free;
end;

jetz empfängt er beim ersten senden die richtig anzahl von daten.
wenn ich allerdings ein 2. mal das gleiche sende sind es etwa 8KB daten zu viel, als wenn noch etwas im chache vom server steht.
wie kann ich die restlichen daten löschen ?


Edit: irgendwie hauts immer noch nicht hin, jetzt fehlen genau 8192 byte



@Astat danke für den eitnrag, werds mir ma anschaun


Edit2: ich hab jetzt gemerkt, wenn ich debugge und sende kommt alles an, lasse ich das programm einfach durchlaufen fehlen immer 8192byte

jokerfacehro 8. Mär 2010 13:04

Re: Übertragungsprotokoll für TSocket ???
 
so ^^

ic hhabs jetz hinbekommen:

ich sende jetzt so:

Datengröße|Befehl|Daten..................

Datengröße besteht aus 4 Byte, somit ist die maximale datengröße auf 4GB begrenzt.
Befehl besteht aus 2Byte und wird gleich extrahiert um schneller entscheiden zu können was mit den restliche daten passieren soll.
Dann folgen die Daten.


Der Client empfängt das erste teilstück und speichert sich die datenlänge ab.
dann empfängt er so viele daten, bis die angegeben datenmenge erreicht ist,
dann schneidet er diese ab, speichert sie zusammen mit datengröße und befehl in einem paket und löst OnExecute aus, wo
der befehl dann verarbeitet wird.

überschüssige daten bleiben im speicher und sind gleichbedeutend mit dem anfang eines neuen paketes.

Astat 8. Mär 2010 15:41

Re: Übertragungsprotokoll für TSocket ???
 
Hallo jokerfacehro, ein JA, wenn die Daten korrekt für jeden Socket (Client-Verbindung) aufbereitet wurden.

D.h. wenn viele Clients am Server, braucht man für jeden Client einen separaten Empfangsbuffer, der so
zu behandeln ist, wie du geschrieben hast.
Globaler Socket Empfangsbuffer --> Dispatch --> zum Client-Buffer.

lg. Astat

jokerfacehro 8. Mär 2010 22:01

Re: Übertragungsprotokoll für TSocket ???
 
ähm ?

zur erläuterung: das ganze läuft am client ab.

der server ist vcl und bekommt, doch eh den socket mitgeliefert für jeden client,
sodass ich direkt im event unterscheiden kann, welcher client gerade spricht und kann das ganze im record zusammenspeichern

Astat 8. Mär 2010 22:14

Re: Übertragungsprotokoll für TSocket ???
 
Zitat:

Zitat von jokerfacehro
ähm ?

Hallo jokerfacehro, auch ähm, es ist Montag und das ist immer ein schlechter Tag für mich!!
Hätte doch genauer lesen sollen, sorry. :wall:

lg. Asat

jokerfacehro 9. Mär 2010 10:13

Re: Übertragungsprotokoll für TSocket ???
 
Zitat:

Zitat von Astat
Zitat:

Zitat von jokerfacehro
ähm ?

Hallo jokerfacehro, auch ähm, es ist Montag und das ist immer ein schlechter Tag für mich!!
Hätte doch genauer lesen sollen, sorry. :wall:

lg. Asat


:cyclops: :mrgreen: kein problem :D


beim datenspeichern mach ich es anders, ich schreibe die datei on the fly, so brauhc ich nicht alles zwischen speichern, das
hat mir 250mb ram gespaart und lieber mit blockwrite anstatt mit write schreiben ^^


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:07 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz