Einzelnen Beitrag anzeigen

dominikkv

Registriert seit: 30. Sep 2006
Ort: Gundelfingen
1.109 Beiträge
 
Delphi 2007 Professional
 
#2

AW: Befehle trennen

  Alt 2. Sep 2012, 21:34
Beim Empfangen musst du vorsichtig sein: Das Ereignis wird aufgerufen, sobald Text empfangen wird. Du weißt nicht, ob die komplette Nachricht schon übertragen wurde oder aber ob vielleicht zwei Nachrichten im Buffer stecken.

Das heißt
- das Event kann für eine Nachricht zwei mal aufgerufen werden
- das Event kann kann zwei Nachrichten enthalten

Darum musst du dir einen eigenen Buffer bauen, in den der empfangene Text landet, und wenn du darin eine komplette Nachricht entdeckst kannst du die da rausholen.

Hier ein Beispiel, wie ich das damals gemacht habe:
Delphi-Quellcode:
const
  MessageDelimitter = '%%';

procedure TMyServer.OnServerClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  msg : string;
  Client: TSClient;
begin
  msg := Socket.ReceiveText;

  if Assigned(fOnRead) then
    fOnRead(self, msg, Socket.RemoteAddress, Socket.RemotePort);

  Client := GetClientByID(GetID(Socket.RemoteAddress, Socket.RemotePort));

  if Assigned(Client) then
    begin
      Client.ReadBuffer := Client.ReadBuffer + msg;

      while Pos(MessageDelimitter, Client.ReadBuffer) > 0 do
        begin
          msg := copy(Client.ReadBuffer, 1, Pos(MessageDelimitter, Client.ReadBuffer) - 1);
          ServerExecute(Client, msg);
          Delete(Client.ReadBuffer, 1, Pos(MessageDelimitter, Client.ReadBuffer) + Length(MessageDelimitter) - 1);
        end;
    end;
end;
Das bedeutet aber, dass du am Ende jeder Nachricht auch ein Zeichen mitsenden musst, dass die Nachricht zu Ende ist. Dann musst du natürlich auch dafür sorgen, dass dieses Zeichen in der eigentlichen Nachricht nicht vorkommt.

Zu deinem Trenner-Problem: Du kannst mit einer TStringList den Text zerlegen.
Delphi-Quellcode:
var
  List: TStringList;
begin
  List := TStringList.Create;
  List.StrictDelimitter := True;
  List.Delimitter := '#';
  List.DelimittedText := 'Wert 1#Wert 2#Banane';

  showmessage(List.Text);
  List.Free;
end;
Ich würde dir aber empfehlen, das ganze zB mit JSON zu verpacken. Dann würde das ganze so aussehen:
Code:
{command:'remoteinfo', body:[name:'Hans', ComUser:'Hans_Workstation', APP_VERSION:123]}
Dann kannst du daraus leicht Objekte machen, zB mit SuperObject. Um mir aus einem Objekt den entsprechenden String zu holen habe ich folgendes benutzt:
Delphi-Quellcode:
function TConverter.GetStr: string;
var
  Context: TSuperRttiContext;
begin
  Context := TSuperRttiContext.Create;

  result := IntToStr(Integer(fType)) + Context.AsJson<TSession>(fObject).AsJSon + MessageDelimitter;

  Context.Free;
end;
Und zurück ging das ganze dann so:

Delphi-Quellcode:
procedure TConverter.SetStr(const Value: string);
var
  Context : TSuperRttiContext;
  Obj : TSession;
  Identifier: TObjIdentifier;
  StrType : string;
  StrObj : string;
begin
  Context := TSuperRttiContext.Create;

  StrType := copy(Value, 1, Pos('{', Value) - 1);
  StrObj := copy(Value, Pos('{', Value), MaxInt);

  Identifier := TObjIdentifier(StrToInt(StrType));

  case Identifier of
    otNone : Obj := NIL;
    otSession : Obj := Context.AsType<TSession>(SO(StrObj));
    otNickChange : Obj := Context.AsType<TNickChange>(SO(StrObj));
    otNachricht : Obj := Context.AsType<TNachricht>(SO(StrObj));
    otKickNachricht: Obj := Context.AsType<TKickNachricht>(SO(StrObj));
    otUserList : Obj := Context.AsType<TUserList>(SO(StrObj));
    otWelcome : Obj := Context.AsType<TWelcome>(SO(StrObj));
  end;

  SetObject(Obj);
  Context.Free;
end;
TNickChange etc sind Klassen von von TSession abgeleitet, damit kannst du dann zB dein Kommando steuern.

Vielleicht hilfts dir
Dominik
Wer anderen eine Grube gräbt, hat ein Gruben-Grab-Gerät!
  Mit Zitat antworten Zitat