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