Скажите, что у меня неправильная идеология в этом коде.
Одной командой я отправляю и получаю ответ без проблем. Но если я хочу (точнее, необходимо отправить его по заданию) N команд и правильно получить все ответы.
Как правильно отправить одну за другой команду, ожидая, пока предыдущая будет полностью завершена.
Отправляя несколько команд, теряя соединение, но иногда пропуская, измените CheckForDataOnSource (100); - не помогает.
Сегодня у меня есть примерно следующий код:
ButtonClick(Sender: TObject);
var
MyServ: TMyServer;
begin
...
MyServ.SendCommand('command 1');
...
MyServ.SendCommand('command N');
end;
unit MyServer;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdContext, IdBaseComponent, IdComponent,
IdCustomTCPServer, IdTCPServer, Vcl.StdCtrls, IdGlobal,
XMLDoc, XMLDOM, XMLIntf, ActiveX, Vcl.ExtCtrls, Vcl.ComCtrls, Base64, IdSync, IdCmdTCPServer,
IdYarn, IdTCPConnection, IdThreadSafe;
type
TMyServer = class(TIdTCPServer)
private
FEndResponse: string;
FTotalStr: string;
procedure Execute(AContext: TIdContext);
//procedure ParseRecv(RecvText: string);
public
procedure Run(BindIP: string; BindPort: Integer);
procedure Stop;
procedure SendCommand(Cmd: string);
constructor Create(AOwner: TComponent);
destructor Destroy; override;
end;
TMySync = class(TIdSync)
protected
procedure DoSynchronize; override;
public
Data: string;
Server: TMyServer;
end;
TMyContext = class(TIdServerContext)
public
Queue: TIdThreadSafeStringList;
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
destructor Destroy; override;
end;
var
FReady: Boolean = True;
implementation
uses Main;
procedure TMySync.DoSynchronize;
begin
//Server.ParseRecv(Data);
MainForm.Memo1.Lines.Add(Data);
end;
constructor TMyServer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ContextClass := TMyContext;
OnExecute := Execute;
FEndResponse := '</response>';
end;
destructor TMyServer.Destroy;
begin
Stop;
inherited Destroy;
end;
constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil);
begin
inherited Create(AConnection, AYarn, AList);
Queue := TIdThreadSafeStringList.Create;
end;
destructor TMyContext.Destroy;
begin
Queue.Free;
inherited Destroy;
end;
procedure TMyServer.Run(BindIP: string; BindPort: Integer);
begin
DefaultPort := 0;
Bindings.Clear;
with Bindings.Add do begin
IP := BindIP;
Port := BindPort;
end;
Active := True;
end;
procedure TMyServer.Stop;
begin
Active := False;
end;
procedure TMyServer.SendCommand(Cmd: string);
var
List: TList;
Ctx: TMyContext;
begin
List := Contexts.LockList;
try
//Connection Server <-> Client once one to one
Ctx := TMyContext(List[0]);
Ctx.Queue.Add(Cmd);
finally
Contexts.UnlockList;
end;
end;
procedure TMyServer.Execute(AContext: TIdContext);
var
Buffer: TIdBytes;
Size, RecvSizeLen: Integer;
RecvStr: string;
Sync: TMySync;
Ctx: TMyContext;
Queue: TStringList;
begin
Buffer := nil;
with AContext.Connection.IOHandler do begin
CheckForDataOnSource(100);
if not InputBufferIsEmpty then begin
Size := StrToInt(ReadLn());
InputBuffer.ExtractToBytes(Buffer);
SetString(RecvStr, PAnsiChar(@Buffer[0]), Size);
FTotalStr := FTotalStr + RecvStr;
if ((Copy(FTotalStr, Length(FTotalStr) - Length(FEndResponse), Length(FEndResponse))) = FEndResponse)
then begin
if Length(FTotalStr) > 0 then begin
Sync := TMySync.Create;
try
Sync.Server := Self;
Sync.Data := FTotalStr;
Sync.Synchronize;
finally
Sync.Free;
end;
end;
FTotalStr := '';
end;
end else begin
Ctx := TMyContext(AContext);
Queue := Ctx.Queue.Lock;
//????????????????????????????????
while (Queue.Count > 0) do begin
try
Ctx.Connection.IOHandler.Write(Queue[0] + #0);
Queue.Delete(0);
finally
Ctx.Queue.Unlock;
end;
end;
end;
end;
end;
end.