AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Code-Bibliothek Library: Internet / LAN / ASP.NET Delphi Sockets: Protokoll für den Datenaustausch
Thema durchsuchen
Ansicht
Themen-Optionen

Sockets: Protokoll für den Datenaustausch

Ein Thema von Zacherl · begonnen am 9. Okt 2006
Antwort Antwort
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#1

Sockets: Protokoll für den Datenaustausch

  Alt 9. Okt 2006, 20:14
Hi,

ihr kennt sicher das Problem, wenn man mit den Sockets arbeitet, dass folgender Aufruf:
Delphi-Quellcode:
Socket.SendText('Hallo');
Socket.SendText('Bye');
Oftmals auch dazu führen kann, dass beim Empfänger "HalloBye" als Text ankommt. Wenn man nun noch mit Befehlen und Parameterstrukturen arbeitet, wird die ganze Sache schon etwas komplizierter ...

Die Befehlsreferenz:
SetParams
Wird eigentlich nicht benötigt, es sei denn, man will die Trenn- und Befehlszeichen ändern.

GetCMDString
Generiert einen Commando String aus einem Befehlswert und Parametern

GetPartitialCMDString
Generiert einen Commando Teilstring aus den Parts

GetLimitedCMDString
Generiert Befehlsblöcke mit einem einstellbaren Zeichenlimit

ParseCommands
Parst einen Commando String und gibt die einzelnen Befehle zurück

ParseParameter
Gibt die einzelnen Parameter + Command eines Befehls zurück

Die Unit:
Delphi-Quellcode:
////////////////////////////////////////////////////////////////////////////////
/// UNIT ProtocolUtils /////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Copyright © 2006 by Florian Bernd ///
/// [url]www.bernd-boppard.de[/url] ///
/// ///
/// Dieses Copyright darf nicht entfernt oder geändert werden! ///
/// Über eine Benennung in den Credits würde ich micht freuen, jedoch ist ///
/// dies nicht zwingend erforderlich. ///
/// ///
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

unit ProtocolUtils;

interface

uses
  Classes, Windows, SysUtils;

//Paramter setzen
procedure SetParams(fDELIMITER, fCMDSIGN, fRETSIGN, fQUOTE, fPQUOTE: Char);
//Commando String erstellen
function GetCMDString(Command: string; Params: array of string): string;
//Teilweisen Commando String erstellen
function GetPartitialCMDString(Parts: array of string; CommandBegin,
  EndOfData: boolean): string;
//Commandos parsen
function ParseCommands(CmdLine, Buffer: string; Commands: TStringList): string;
//Commandostring erstellen und nach Zeichen begrenzt ausgeben
procedure GetLimitedCMDString(Command: string; Params: array of string;
  Limit: integer; Parts: TStringList);
//Die Parameter eines Befehls bekommen
procedure ParseParameter(Command: string; Params: TStringList);

var
  DELIMITER: Char = '|'; //Trennzeichen für Parameter
  CMDSIGN : Char = '*'; //Trennzeichen für die Befehle
  RETSIGN : Char = '#'; //Endzeichen für einen Befehl
  QUOTE : Char = '"'; //Quote Zeichen für die Befehle
  PQUOTE : Char = '~'; //Quote Zeichen für die Parameter

implementation

//Splittet einen Text anhand eines Delimiters in seine Einzelteile auf
function Split(const fText: String; const fSep: Char; fTrim: Boolean = false;
  fQuotes: Boolean = false; QuoteChar: Char = '"'): TStringList;
var
  vI,
  vOffset: Integer;
  vBuffer: String;
  vOn: Boolean;
begin
  Result := TStringList.Create;
  vBuffer := '';
  vOffset := 0;
  vOn := true;
  for vI := 1 to length(fText) do
  begin
    if (fQuotes and (fText[vI] = fSep ) and vOn) or (not (fQuotes) and (fText[vI] = fSep)) then
    begin
      if fTrim then vBuffer := Trim(vBuffer);
      if vBuffer = 'then vBuffer := fSep; // !!! sonst läuft z.B. split(',**',',') auf einen Hammer...
      if vBuffer[1] = fSep then
        vBuffer := Copy(vBuffer, 2, Length(vBuffer));
      Result.Add(vBuffer);
      vBuffer := '';
    end;
    if fQuotes then
    begin
      if fText[vI] = QuoteChar then
      begin
        vOn := Not(vOn);
        if Copy(fText, vI + vOffset, 2) = QuoteChar + QuoteChar then
        begin
          vBuffer := vBuffer + QuoteChar;
          vOffset := vOffset + 1;
        end
          else
        begin
          vOffset := 0;
        end;
        Continue;
      end;
      if (fText[vI] <> fSep) or ((fText[vI] = fSep) and (vOn = false)) then
        vBuffer := vBuffer + fText[vI];
    end else
      if fText[vI] <> fSep then
        vBuffer := vBuffer + fText[vI];
  end;
  if vBuffer <> 'then
  begin
    if fTrim then vBuffer := Trim(vBuffer);
      Result.Add(vBuffer);
  end;
end;

//Ersetzt einfache Quotes in durch Zweifache
function Prepare(Text: string): string;
begin
  Result := StringReplace(Text, QUOTE, QUOTE + QUOTE, [rfReplaceAll]);
  Result := StringReplace(Result, PQUOTE, PQUOTE + PQUOTE, [rfReplaceAll]);
end;

procedure SetParams(fDELIMITER, fCMDSIGN, fRETSIGN, fQUOTE, fPQUOTE: Char);
begin
  DELIMITER := fDELIMITER;
  CMDSIGN := fCMDSIGN;
  RETSIGN := fRETSIGN;
  QUOTE := fQUOTE;
  PQUOTE := fPQUOTE;
end;

function GetCMDString(Command: string; Params: array of string): string;
var
  i: integer;
begin
  //Befehl hinzufügen
  Result := QUOTE + CMDSIGN + PQUOTE + Prepare(Command) + PQUOTE + DELIMITER;

  //Alle Parameter hinzufügen
  for i := 0 to length(Params) -1 do
  begin
    Result := Result + PQUOTE + Prepare(Params[i]) + PQUOTE + DELIMITER;
  end;

  //Abschließende Befehlszeichen hinzufügen
  Result := Result + QUOTE + RETSIGN + CMDSIGN;
end;

function GetPartitialCMDString(Parts: array of string; CommandBegin,
  EndOfData: boolean): string;
var
  i: integer;
begin
  //Wenn CommandBegin, dann wird der erste Teil als Command verwendet
  if CommandBegin then
    Result := QUOTE + CMDSIGN + PQUOTE;

  //Alle Teile hinzufügen
  for i := 0 to length(Parts) -1 do
  begin
    if CommandBegin then
      Result := Result + PQUOTE + DELIMITER + PQUOTE + Prepare(Parts[i]) + PQUOTE
    else
      Result := Result + DELIMITER + PQUOTE + Prepare(Parts[i]) + PQUOTE
  end;

  //Wenn EndOfData, dann werden die abschließenden Befehlszeichen angehängt
  if EndOfData then
    Result := Result + DELIMITER + QUOTE + RETSIGN + CMDSIGN;
end;

function ParseCommands(CmdLine, Buffer: string; Commands: TStringList): string;
var
  i: integer;
  CMDList: TStringList;
begin
  //Comammands leeren
  Commands.Clear;
  try
    CMDList := Split(Buffer + CmdLine, CMDSIGN, false, true, QUOTE);

    //Wenn kein vollständiger Befehl vorhanden ist ...
    if CMDList.Count < 1 then
    begin
      //... und der Buffer nicht leer ist ... (Der Befehl kann nie vollständig
      //werden, wenn nicht mindestens das Befehlszeichen im Buffer ist)
      if Buffer <> 'then
      begin
        //... den neuen Buffer zurückgeben und die Stringliste leeren
        Result := Buffer + CmdLine;
        CMDList.Clear;
      end;
    end
      else
    begin
      //Wenn mindestens ein vollständiger Befehl vorhanden ist die Befehlsliste
      //in einer Schleife durchgehen und ...
      for i := 0 to CMDList.Count -1 do
      begin
        //... fals das letzte Zeichen nicht das abschließende Befehlszeichen ist
        //...
        if Copy(CmdList[i], length(CmdList[i]), 1) <> RETSIGN then
        begin
          //... muss dies die letzte Zeile der Stringliste sein und somit ist
          //auch klar, dass der letzte Befehl nicht vollständig ist. Daher wird
          //die komplette letzte unvollständige Befehlszeile als neuer Buffer
          //zurückgegeben
          Result := QUOTE + CmdList[i];
        end
          else
        begin
          //... fals doch, dann enthält die aktuelle Zeile einen vollständigen
          //Befehl und kann in der Commando Stringliste eingetragen werden
          Commands.Add(Copy(CMDList[i], 1, length(CmdList[i]) -1));
        end;
      end;
    end;
  finally
    CMDList.Free;
  end;
end;

procedure GetLimitedCMDString(Command: string; Params: array of string;
  Limit: integer; Parts: TStringList);
var
  i: integer;
  TmpCmd,
  TmpPart: string;
begin
  //Die Ergebnissliste leeren
  Parts.Clear;
  //Einen CMDString mit dem vorgegebenen Parametern generieren
  TmpCmd := GetCMDString(Command, Params);
  //Das Ergebniss in einer Schleife durchgehen und immer Limit Zeichen in die
  //Ergebnissliste kopieren
  for i := 0 to (length(TmpCmd) div Limit) do
  begin
    TmpPart := Copy(TmpCmd, (i * Limit) +1, Limit);
    if TmpPart <> 'then
      Parts.Add(TmpPart);
  end;
end;

procedure ParseParameter(Command: string; Params: TStringList);
var
  ParamList: TStringList;
begin
  ParamList := TStringList.Create;
  try
    //Die Parameter eines Befehls zurückgeben
    ParamList := Split(Command, DELIMITER, false, true, PQUOTE);
    Params.Text := ParamList.Text;
  finally
    ParamList.Free;
  end;
end;

end.
Allerdings könnte es Probleme geben, wenn ein RETSIGN im Befehl vorkommt und das RETSIGN zufällig das letzte gesendete Zeichen von einem Block ist. Leider habe ich noch keinen Ansatz gefunden, wie ich dieses Problem vermeiden kann.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Antwort Antwort

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:53 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