LNet Daten übertragen wie am Besten?

Alle Fragen zur Netzwerkkommunikation
Antworten
laz847
Beiträge: 114
Registriert: Mi 18. Jun 2014, 16:39

LNet Daten übertragen wie am Besten?

Beitrag von laz847 »

Hi Leute, mir qualmt der Schädel, ich weiß nicht wie ich folgendes Problem am effektivsten löse. Ich verwende LNet in einer dll, also die nonvcl Version. Ich hab mir das Beispiel (examples/console/ltcp) soweit umgebaut und erweitert das ich fast am Ziel bin.

Nun muss ich vom Client(MT4,Mql4) >>> mittels DLL (Lazarus) >>> Server(Lazarus) folgendes senden:

(A) IN ECHTZEIT >>> Timer(1sec) >>> kurze Strings max. 100 zeichen >>> "XYZZZZ|11.21321|23.23232|23.232"

Und das geht auch, damit hab ich kein Problem.

(B) WENN ANGEFORDERT >>> SERVER >>> GET_DATA_XYZ >>> double array[][]/Structur/PackedRecord
siehe http://www.mql5.com/en/docs/constants/structures/mqlrates

Code: Alles auswählen

struct MqlRates
  {
   datetime time;            // Period start time
   double   open;           // Open price
   double   high;           // The highest price of the period
   double   low;             // The lowest price of the period
   double   close;           // Close price
   long     tick_volume;  // Tick volume
   int      spread;            // Spread
   long     real_volume;  // Trade volume
  };

Da ich ja eh schon Strings (A) nutze, dachte ich mir, es wäre wohl am sinnvollsten wenn ich (B) auch in einen Stream oder Packed Record packe??

Ich hab mir bei LNet alles durchgelesen, hier im Forum hab ich alles über LNet gelesen, so richtig sicher bin ich mir jetzt nicht wie es richtig is, manche warten auf OnCanSend, andere prüfen nur die Rückgabe von SendMessage=0 ???

Code: Alles auswählen

{
///////////////////////////////////////////////////////////////////////////////////////////////////////
http://lnet.wordpress.com/usage/sockets ... d-sending/
}

procedure TMyClass.OnCanSend(aSocket: TLSocket);
var
  Sent: Integer; // number of bytes sent each try
  TempBuffer: string = ''; // our local temp. buffer for the filestream, can be done smarter tho
begin
  repeat
    if Length(TempBuffer) = 0 thenTempBuffer := GetNewChunk; // get next chunk if we sent all from the last one
    Sent := FConnection.SendMessage(TempBuffer, aSocket);    // remember, don't use the aSocket directly!
    Delete(TempBuffer, 1, Sent);                                                // delete all we sent from our temporary buffer!
  until (Sent = 0) or (AllIsSent);                                                  // try to send until you can't send anymore
end;
{
///////////////////////////////////////////////////////////////////////////////////////////////////////
viewtopic.php?p=29832#p29832
}

var data: string;
function GetNewChunk: string;
begin
  result := copy(data, 1, 65535);
  delete(data, 1, 65535);
end;
{

Ich starte also den ersten Sendevorgang wie gewohnt nur jetzt mit GetNewChunk, wenn mein String 10 Zeichen hat geht der so durch, OnCanSend (feuert nur wenn der Puffer mal am Anschlag war?) macht dann eben nichts. Kommt dann aber ein Array oder ein Stream > 65535 wird der zerschnitten und die Daten geteilt versendet?

(1) Denke mal so sollte es korrekt sein oder?

(2) Die Daten kommen ja in der dll (Lazarus/Client) im Klartext an, als Array oder String. Welches Format ist geeignet?

Ich würde TFileStream nehmen, http://www.delphi-treff.de/tipps-tricks/object-pascal/arrays/dynamisches-array-speichern/ ???
procedure SaveArray(const AFilename: string; const AArrayData: TArrayData);
procedure LoadArray(const AFilename: string; var AArrayData: TArrayData);

(3) Was passiert in der Zeit mit (A) den Daten die in Echtzeit übertragen werden sollten? Ich gehe davon aus das die Verbindung schnell ist, ist TCP localhost so schnell wie die HDD? Wäre es sinnvoller einen 2 Client über einen anderen Port oder 2 Client / 2 Server einzurichten für die Übertragung von grossen Datensätzen oder geht das gleichzeitig irgendwie über einen Kanal?

Vielen lieben Dank und sorry für den langen Text :oops:

laz847
Beiträge: 114
Registriert: Mi 18. Jun 2014, 16:39

Re: LNet Daten übertragen wie am Besten?

Beitrag von laz847 »

Ok eine Antwort zu (1) habe ich gefunden, das könnte echt besser dokumentiert sein :oops:

You need to "send" in a loop until send fails (returns 0). Only then you know that you can't send so "OnCanSend" will get fired again. This is perhaps a bit confusing, but the meaning of "OnCanSend" is what is called "edge-triggered" in that it will fire ONLY when the status changes from "I can still send" into "I can't send anymore" and then to "I can send again". So basicly you should add an inner loop which sends until Send returns 0 or all data is sent. If you need to see in code, look at the lftpclient example, which does this when sending files to the server.
http://wiki.lazarus.freepascal.org/Talk:lNet

Allerdings wird in dem "lftpclient example" das "OnCanSend" gar nicht verwendet :cry:

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: LNet Daten übertragen wie am Besten?

Beitrag von corpsman »

Servus,

in Send_Get_File kannst du sehen, wie man einzelne "Große" Dateien übers Netz und im Lan übertragen kann, evtl hilft dir das weiter.
--
Just try it

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: LNet Daten übertragen wie am Besten?

Beitrag von Socke »

laz847 hat geschrieben:(3) Was passiert in der Zeit mit (A) den Daten die in Echtzeit übertragen werden sollten? Ich gehe davon aus das die Verbindung schnell ist, ist TCP localhost so schnell wie die HDD? Wäre es sinnvoller einen 2 Client über einen anderen Port oder 2 Client / 2 Server einzurichten für die Übertragung von grossen Datensätzen oder geht das gleichzeitig irgendwie über einen Kanal?

Wie schnell Daten von einem Programm zu einem anderen auf dem selben Betriebssystem über "das Netzwerk" übertragen werden, hängt stark von dem verwendeten Betriebssystem ab. Linux ist hier wesentlich schneller als Windows; es gibt hier übrigens keinen Grund eine HDD/Festplatte anzunehmen. Wenn man das will, kann man den Datenaustausch auch direkt über die Festplatte machen. Im Normalfall bleibt alles im Arbeitsspeicher.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: LNet Daten übertragen wie am Besten?

Beitrag von Christian »

Kannst du irgendwie belegen, das Linux eine schnellere IP Stack implementierung hat als Windows ?
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: LNet Daten übertragen wie am Besten?

Beitrag von Socke »

Christian hat geschrieben:Kannst du irgendwie belegen, das Linux eine schnellere IP Stack implementierung hat als Windows ?

Nein, nicht direkt; ich hatte nur vor einiger Zeit gelesen, dass Linux über die loopback-Schnittstelle recht effizient arbeitet während Windows alles quasi ins Netzwerk "sendet" auch wenn es für Localhost bestimmt ist.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

laz847
Beiträge: 114
Registriert: Mi 18. Jun 2014, 16:39

Re: LNet Daten übertragen wie am Besten?

Beitrag von laz847 »

Nach einigen fehlgeschlagenen Versuchen starte ich jetzt nochmal am Anfang und mach es Stück für Stück mit Eurer Hilfe. Habe mich mehrmals verzettelt und mir noch mehr Fehler eingebaut, damit es nicht zuviel auf einmal wird, werde ich mich Frage für Frage vorkämpfen :D. Ich bedanke mich jetzt schon für die Hilfe!!!!

@corpsman Tut mir leid ich habe mir das angesehen aber ich kriege das nicht umgebaut für meine Zwecke, Du kannst mir aber sicher helfen, für Dich sollte das ein Klacks sein :D

Code: Alles auswählen

{ MqlRates ------------------------------------------------------------------------------------------------------------- }
  TRatesStruct = packed record
   time        : INT64;   // datetime | 8 byte
   open        : Double;  // double   | 8 byte
   high        : Double;  // double   | 8 byte
   low         : Double;  // double   | 8 byte
   close       : Double;  // double   | 8 byte
   tick_volume : UINT64;  // long     | 8 byte
   spread      : INT32;   // int      | 4 byte
   real_volume : UINT64;  // long     | 8 byte
  end;                    // --------> 60 byte
 
  TRatesArray = Array of TRatesStruct;
 
{ MqlTick ------------------------------------------------------------------------------------------------------------- }
 TTicksStruct = packed record
  time   : INT64;  // datetime  | 8 byte
  bid    : Double; // double    | 8 byte |
  ask    : Double; // double    | 8 byte
  last   : Double; // double    | 8 byte
  volume : UINT64; // ulong     | 8 byte
  end;             // ---------> 40 byte
 
  TTicksArray = Array of TTicksStruct;


In meiner DLL kommen ein PWIDECHAR und 2 x 2d Arrays Q[][struct] / R[][struct] mit Packed Records per & Referenz an, diese möchte ich per TCP weitergeben, dafür verwende ich die lnet nonvcl.

Wenn die 2 Arrays leer sind -> soll nur der PWideChar weitergeleitet werden, das ist einfach, das habe ich schon: :D

Code: Alles auswählen

function TCPx.IpcSend(const _msg:PWideChar;const _qac:Integer;const _Quotes:TTicksArray;const _rac:Integer;const _Rates:TRatesArray):integer;
var
 data_sent:integer;
begin
 
 if(FClient.Connected) and (_qac=0) and (_rac=0) then begin
  FClient.SendMessage(AnsiString(_msg));
  exit(1);
 end;
 
  if(_msg='QUOTES') and (_qac>0) then IcpStream(_msg,_qac,_Quotes,0,_Rates);   
..............
end;


Bis hierhin bin ich gekommen :D, wie sende ich die 2 Records und den Header über TCP und lese den aus?

Ich wollte alles in einen Memorystream speichern "IcpStream(_msg,_qac,_Quotes,0,_Rates)" und dann versenden, das ging aber schief, am anderen Ende konnte ich nichts mehr auslesen.

Code: Alles auswählen

TIpcHead     = record
   head_txt    : ShortString;//
   head_size   : Integer;    // SizeOf(header[0])
   elem_count  : Integer;    // Length(Array)
   elem_size   : integer;    // SizeOf(Array)
   data_size   : Integer;    // elem_count * elem_size
   full_size   : Integer;    // head_size + (elem_length * elem_size)
  end;
 
function TCPx.IcpStream(const _msg:PWideChar; const _qac:Integer;const _Quotes:TTicksArray;const _rac:Integer;const _Rates:TRatesArray ):integer;
 var
 header : array[0..1] of TIpcHead;
 i          : integer;
begin 
 
 if(_msg='QUOTES') then begin
  header[0].head_txt    := '@QUOTES';
  header[0].head_size   := SizeOf(header[0]);
  header[0].elem_count  := _qac;
  header[0].elem_size   := SizeOf(TTicksStruct);
 end;
 
 header[0].data_size   := header[0].elem_count * header[0].elem_size;
 header[0].full_size   := header[0].head_size  + header[0].data_size;
.........
   // write header to stream
   TMStream.Clear;
   TMStream.Position:=0;
   TMStream.WriteBuffer(header[0],SizeOf(header[0]));
 
   // write _Quotes to stream
   if(_qac>0) then begin
    for i :=0 to (_qac-1) do TMStream.WriteBuffer(_Quotes[i],SizeOf(_Quotes[i]));
   end;   
 
 


An dem @ will ich beim Empfänger den Stream erkennen, ist da bisher irgendwas falsch?

laz847
Beiträge: 114
Registriert: Mi 18. Jun 2014, 16:39

Re: LNet Daten übertragen wie am Besten?

Beitrag von laz847 »

Ok hat sich erledigt, wer mal danach sucht, mit ein paar Änderungen bekommt man dieses Beispiel lauffähig:

http://www.michael-puff.de/Programmierung/Delphi/Code-Snippets/MMF.shtml

Lieber Michael, dickes Danke von hier you make my day :D :D :D :D :D

Memory Mapped Files und es geht aus einer dll, so ein Beispiel habe ich gesucht :lol:

Antworten