Autor Beitrag
alexschultze
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 317



BeitragVerfasst: So 29.12.02 23:18 
hiho,

ich benutze jetzt CLientSocket und Serversocket für meine Applikation. Der Server schreibt, wenn er ein bestimmtes Datenpaket erhält, einen String und einen Record (extra in den Buffer).

Das funktioniert alles prima, aber sobald man diese Prozedur zu oft und schnell hintereinander ausführt, 'pappen' die Informationen zusammen.

Kann ich diese irgendwie auseinanderhalten? FlushBuffers o.ä. gibt es nicht.

Ich konnte Abhilfe schaffen, indem ich eine sleep(10000) FUnktion testweise eingebaut habe, aber das nützt ja nichts...

alles unter sleep(300) bringt ohnehin nichts, weiter habe ich nicht probiert.


Ach so, was noch wichtig ist: Dieser Fehler tritt nur (oder besser: vermehrt) im Internet auf.
Lokal und Lan sind kein problem.


Ich denke das es was mit den Latenz(=Ping) Zeiten zu tun hat, aber was kann ich tun?! :(
Savage
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 110



BeitragVerfasst: Mo 30.12.02 10:53 
das ist ein typisches Problem bei diesen Komponenten, ich habe es gelöst, indem ich vom Server bzw. Clienten nach empfang eines (kompleten) Packetes eine Bestätigung gesendet hab und erst nach erhalt dieser Bestätigung wird weiter gesendet.

MfG
Savage
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 30.12.02 11:10 
Hi!

Da du doch schon festgestellt hast, das mehrere Informationen in einem Ereignis ankommen können, geh doch einfach darauf ein! Schau wieviele Bytes Daten angekommen sind, und splitte diese in die einzelnen Infos auf.

Cu,
Udontknow
Jack Falworth
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222

Win XP Pro, Slackware 10.0
D5 Enterprise, C++, ABAP
BeitragVerfasst: Mo 30.12.02 13:22 
probier doch mal Application.Processmessages. Dann wird erst das Paket geschickt und wenns fertig ist das nächste.

MfG

Jack Falworth

_________________
Andere zu kritisieren ist mitunter eine Möglichkeit, sich selbst ins bessere Licht zu setzen.
alexschultze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 317



BeitragVerfasst: Mo 30.12.02 19:20 
Application.Processmessages??

Klingt sehr gut! ABer wie wende ich das an!? Kleinen Tipp?

Das mit dem senden und Bestätigung abwarten habe ich auch im Hinterkopf. ABer das ist eine Notlösung. Ich plane recht viele gleichzeitig eingeloggte User ein, und dann ein Management zu erstellen könnte schwer werden.

Das mit dem Splitten kann ich mir persönlich überhaupt nix funktionierendes drunter vorstellen. Das ist auch meist recht willkürlich ob er überhaupt zusammenhängt.

Bin gespannt was man mit diesem Processmessages machen kann. Krieg ich bitte noch mehr Infos dazu?
Jack Falworth
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222

Win XP Pro, Slackware 10.0
D5 Enterprise, C++, ABAP
BeitragVerfasst: Mo 30.12.02 20:35 
1) trockene Theorie (mit freundlicher Unterstützung der allwissenden Delphi Hilfe):

Mit der Methode ProcessMessages können Sie eine Anwendung unterbrechen, so daß Windows die Botschaftswarteschlange verarbeiten kann.

procedure ProcessMessages;

Beschreibung

Durch einen Aufruf von ProcessMessages ermöglichen Sie es Windows, die Botschaften abzuarbeiten, die sich in der Botschaftswarteschlange befinden. Mit der Methode ProcessMessages kann die Botschaftswarteschlange von Windows durchlaufen werden, bis diese leer ist. Anschließend wird die Ablaufsteuerung wieder auf die Anwendung übertragen.

Hinweis

Die Vernachlässigung der Botschaftsverarbeitung wirkt sich nur auf die Anwendung aus, die ProcessMessages aufruft, nicht auf andere Anwendungen. Bei langen Operationen ermöglicht der periodische Aufruf von ProcessMessages, daß die Anwendung auf Zeichnen- und andere Botschaften antwortet.

2) Praxis

Nehmen wir an (ich weiß nicht was für einen Code du benutzt), du schickst mit einer Schleife Datenpakete an einen Client/Server.
Da das nächste Paket direkt hinter dem vorderen geschickt wird und das vordere noch nicht fertig ist, gibt es einen Daten "Misch Masch" (Müll) mit dem man später nichts mehr anfangen kann.
Jetzt musst du in deine Schleife den Befehl Application.Processmessages einbauen (hinter den senden Befehl). Dann wird das Datenpaket gesendet und der Befehl hält praktisch die Schleife an und wartet bis das Datenpaket komplett ist und schickt dann das nächste los.

Hoffentlich hab ich mich einigermaßen verständlich ausgedrückt :roll:

MfG

Jack Falworth

_________________
Andere zu kritisieren ist mitunter eine Möglichkeit, sich selbst ins bessere Licht zu setzen.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 30.12.02 22:20 
@Jack Falworth:

Du musst gar keine so große Anstrengung unternehmen, um die Datenpakete immer einzeln zu bekommen, daß schlägt sowieso früher oder später fehl (nämlich genau dann, wenn der VCL-Hauptthread ger nicht schnell genug die Pakete abarbeiten kann, so eine Situation kann mit noch so vielen Application.Proccessmessages nicht völlig verhindert werden, da z.B. andere Prozesse höherer Priorität dem Programm nicht mehr genügend Rechenzeit übriglassen könnten, um selbst ohne anderweitige programminterne Auslastung die Pakete abzuarbeiten).

Was du als Mischmasch und unauflösbaren Datenmüll bezeichnest, ist in Wirklichkeit eine Kleinigkeit:

Du musst einfach nur die Größe bzw. den Inhalt deiner Pakete bestimmen können!

Du sendest einen String? Dann packe zunächst ein Byte mit dem Wert 0 in den zu sendenden Stream. Anschliessend (zwei Byte dürften reichen) die Länge des Strings und dann den String ebenfalls einfach reinschieben.

Du sendest einen Record mit statischer Grösse? Dann das erste Byte z.B. eine 1 als Identifikation und dann den Record hinein in den sendenden Stream.

Auf Empfängerseite kannst du dann einfach den Stream entlanglesen.
Zunächst Identifikationsbyte einlesen. Daran erkennst du, ob es sich um einen String oder einen Record handelt.
Ist es ein String, liest du zunächst weitere 2 Byte (1 Word) ein und hast nun die Anzahl der Zeichen, die noch folgen. Diese liest du dann auch ein.
Ist es ein Record musst du diesen nur einlesen. Das war´s.
Solltest du dann feststellen, daß im Stream noch mehr Daten sind (Stream.Position<Stream.Size), bedeutet das, das noch ein Paket hintendran hängt. Hier fängst du einfach wieder von vorne an: Identifikation, usw...

Cu, :)
Udontknow
alexschultze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 317



BeitragVerfasst: Di 31.12.02 13:05 
argh klingt das kompliziert. Mit diesem ProcessMessages könnte es kritisch sein. Was passiert mit neuen Paketen die ankommen? Ich habe da Angst vor 'Datenstau' ...


Das mit dem Trennen via dem Bit...

also, da bräuchte ich erstmal mehrere Bit, denn ich habe in meinem Programm mehrere Recordtypen und Nachrichten. Hast du mal ein kurzes Beispiel wie ich aus dem Buffer ein Bit auslesen kann?
Moritz M.
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1672



BeitragVerfasst: Di 31.12.02 15:01 
Ich hatte das ganze Problem auchmal mit nem Chatserver & Client, ich habs aufgegeben.
Aber du hast die Möglichkeit das ganze mit Indy zu machen, da gibts dann den Befehl WriteLn (kennen warscheinlich viele aus anderen programmiersprachen), da geht dann alles Mühelos. Mit Indy TCP/IP Clients und Servern hab ich alledrdings schelchte Erfahrungen gemacht, weil die, sobald der jeweils andere Disconnected, ne Mega Fehlermeldung ausspeihen bei der ichs noch nicht geschafft hab, sie zu unterdrücken *hrmpf*
Das mit der Empfangsbestätigung ist die beste Lösung(finde ich). Nur leider läuft das nur mit Server->Client und nicht andersrum, da sich die Cleints ja nich ohne Server verständigen können. Du könntest natürlich für jeden Client nen extra Port starten, das ist aber eher dumm.
Es wäre auch eine Möglichkeit, dass jede Message die Ankommt eine bestimmte Größe haben muss, z.b. 50 Zeichen. Falls die ankommende Mess mehr hat, wir sie zu jeweils 50er gesplittet und einzeln ausgewertet.
Du musst dir halt ein zeichen rausnehmen, dass du Verbieten muss und als Leerzeichen(Zum füllen bis auf 50 zeichen) verwendest, das dann in der Auswertung ignoriert wird.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mi 01.01.03 14:37 
@Alex:

Ich sprach von einem Byte (8 Bit), damit lassen sich also 256 verschiedene Typen von Daten übertragen.

Hier mal ein Beispiel für das Senden & Empfangen eines Records, eines Integerwertes und einem String[50]:

ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
var IDByte:Byte;
var MyRecord:TMyRecord;
var Str:String[50];
var Int:Integer;

procedure TForm1.SendInfo;
var Stream:TMemoryStream
begin
  //Erstellen eines MemoryStreams, um dessen Inhalt dann zu versenden
  Stream:=TMemoryStream.Create;
  try
    //ID 1 festlegen (steht für Daten vom Typ TMyRecord)
    IDByte:=1;
    //IDByte in den Stream schreiben 
    Stream.Write(IDByte,SizeOf(IDByte));
    //Record in den Stream schreiben
    Stream.Write(MyRecord,SizeOf(MyRecord));

    //ID 2 festlegen (steht für Daten vom Typ Integer)
    IDByte:=2;
    //IDByte in den Stream schreiben 
    Stream.Write(IDByte,SizeOf(IDByte));
    //Integer in den Stream schreiben
    Stream.Write(Int,SizeOf(Int));

    //ID 3 festlegen (steht für Daten vom Typ String[50])
    IDByte:=3;
    //IDByte in den Stream schreiben 
    Stream.Write(IDByte,SizeOf(IDByte));
    //String[50] in den Stream schreiben
    Stream.Write(Str,SizeOf(Str));

  finally 
    //Stream senden, Stream wird danach freigegeben. 
    MyClientSocket.Socket.SendBuf(Stream.Memory^,Stream.Size); 
    Stream.Free; 
  end;
end;

procedure TForm1.Empfangen(Socket:TCustomWinSocket); 
var Stream:TMemoryStream; 
var Buffersize:Integer; 
begin 
  //Stream erstellen, in ihn werden die empfangenen Daten gespeichert. 
  Stream:=TMemoryStream.Create; 
  try 
    //Anzahl empfangener Bytes ermitteln 
    Buffersize:=Socket.ReceiveLength; 
    Stream.Size:=BufferSize; 
    //empfangene Daten in Stream schieben 
    Socket.ReceiveBuf(Stream.Memory^,Buffersize); 
    //Streamposition an den Anfang setzen 
    Stream.Position:=0; 

    //Nun Streamdaten auswerten 

   While Stream.Position<Stream.Size do 
   begin 
      //IDByte einlesen 
      Stream.ReadBuffer(IDByte,SizeOf(IDByte)); 
      if IDByte=1 then 
        Stream.ReadBuffer(MyRecord,SizeOf(MyRecord)); 
      if IDByte=2 then 
        Stream.ReadBuffer(Int,SizeOf(Int)); 
      if IDByte=3 then 
        Stream.ReadBuffer(Str,SizeOf(Str)); 
    end; 
    finally 
      //Stream freigeben 
    Stream.Free; 
  end; 
end;

Cu, :)
Udontknow

Edit: Korrekturen von unterem Post eingefügt.


Zuletzt bearbeitet von Udontknow am Do 18.03.04 13:40, insgesamt 1-mal bearbeitet
alexschultze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 317



BeitragVerfasst: Mi 01.01.03 17:44 
genial, danke.

Kann es nicht passieren, das z.B. das zweite Paket nicht ganz sondern nur halb hintern dran hängt?
alexschultze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 317



BeitragVerfasst: Mi 01.01.03 19:23 
mh. außerdem kommt wenn ich einen Stream sende nichts an!!!!
????!?!??
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure TForm4.Button9Click(Sender: TObject);
var
Stream2:TMemoryStream;
Record_2command:TRecord_2command;
begin
//Erstellen eines MemoryStreams, um dessen Inhalt dann zu versenden 
  Stream2:=TMemoryStream.Create;
  try 
    //ID 1 festlegen (steht für Daten vom Typ TMyRecord) 
    IDByte:=1;
    //IDByte in den Stream schreiben
    Stream2.Write(IDByte,SizeOf(IDByte));
    //Record in den Stream schreiben
     record_2command.SessionPW:=SessionPW;
 record_2command.command:='Mein Befehl';
    Stream2.Write(record_2command,SizeOf(Trecord_2command));


  finally 
    //Stream senden, Stream wird danach automatisch freigegeben. 
    Clientsocket1.Socket.SendStream(Stream2);
  end;


Der Server merkt nicht einmal das man versucht hat was zu senden! Gar nichts!
(Clientsocket1.onRead)
S - tefano
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28



BeitragVerfasst: Mi 01.01.03 20:57 
Musst du nicht, wenn du mit nem Client etwas verschickst, das OnReadEreignis des Serversockets benutzen?

_________________
Es gibt Tage, an denen verliert man, und es gibt Tage, an denen gewinnen die anderen.
Walk on
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Do 02.01.03 09:43 
Ja klar musst du. Aber ist es so schwer, im Ereignis diese Prozedur aufzurufen?

@Alex: Nein, dass Pakete halb ankommen, kann nicht passieren, dafür sorgt das TCP-Protokoll.

Ich schaue mir das mal an...

Cu,
Udontknow
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Do 02.01.03 10:40 
Okay, da waren ein paar Schwächen im Beispiel...

Zunächst mal scheint Sendstream tatsächlich nicht zu funktionieren. Das ist aber kein Problem. Ersetze den Finally-Inhalt mit diesem:

ausblenden Quelltext
1:
2:
3:
4:
5:
finally
  //Stream senden, Stream wird danach freigegeben.
  MyClientSocket.Socket.SendBuf(Stream.Memory^,Stream.Size);
  Stream.Free;
end;


Die Prozedur Empfangen habe ich auch ein wenig falsch erstellt. Man muss natürlich den Socket benutzen, den einem das Ereignis OnClientRead liefert, wolltest du das sagen, S-Tefano?

Also :

ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
procedure TForm1.Empfangen(Socket:TCustomWinSocket);
var Stream:TMemoryStream;
var Buffersize:Integer;
begin
  //Stream erstellen, in ihn werden die empfangenen Daten gespeichert.
  Stream:=TMemoryStream.Create;
  try
    //Anzahl empfangener Bytes ermitteln
    Buffersize:=Socket.ReceiveLength;
    Stream.Size:=BufferSize;
    //empfangene Daten in Stream schieben
    Socket.ReceiveBuf(Stream.Memory^,Buffersize);
    //Streamposition an den Anfang setzen
    Stream.Position:=0;

    //Nun Streamdaten auswerten

   While Stream.Position<Stream.Size do
   begin
      //IDByte einlesen
      Stream.ReadBuffer(IDByte,SizeOf(IDByte));
      if IDByte=1 then
        Stream.ReadBuffer(MyRecord,SizeOf(MyRecord));
      if IDByte=2 then
        Stream.ReadBuffer(Int,SizeOf(Int));
      if IDByte=3 then
        Stream.ReadBuffer(Str,SizeOf(Str));
    end;
    finally
      //Stream freigeben
    Stream.Free;
  end;
end;


Cu,
Udontknow
S - tefano
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28



BeitragVerfasst: Do 02.01.03 12:23 
@Udontknow
genau, das wollt ich ausdrücken. Vielleicht kams n bissken schlecht rüber, hatte die letzten beiden Tage nich gaaaanz so viel Schlaf wie sonst...

_________________
Es gibt Tage, an denen verliert man, und es gibt Tage, an denen gewinnen die anderen.
Walk on