0
votes

everyone. I have a sample code that Mr Remy Lebeau gave me. That is about the Indy Server... But, this code doesn't work on my Delphi environment. My delphi version is 2010, and Indy version is notified 10.5.5

My delphi doesn't recognize TIdThreadSafeObjectList, TIdContextThreadList

type
  TMonitorContext = class(TIdServerContext)
  public
    Screenshots: TIdThreadSafeObjectList;
    ScreenshotEvent: THandle;
    constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
    destructor Destroy; override;
  end;

  TScreenshotInfo = class
  public
    ClientIP: string;
    ClientPort: TIdPort;
    Data: TMemoryStream;
    constructor Create;
    destructor Destroy; override;
  end;

constructor TMonitorContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList);
begin
  inherited;
  Screenshots := TIdThreadSafeObjectList.Create;
  Screenshots.OwnsObjects := True;
  ScreenshotEvent := CreateEvent(null, True, False, nil);
end;

destructor TMonitorContext.Destroy;
begin
  Screenshots.Free;
  CloseHandle(ScreenshotEvent);
  inherited;
end;

constructor TScreenshotInfo.Create;
begin
  inherited;
  Data := TMemoryStream.Create;
end;

destructor TScreenshotInfo.Destroy;
begin
  Data.Free;
  inherited;
end;

{one side----idTCPServerRecv is to receive screenshot streams from clients}

procedure TIndyServerForm.IdTCPServer_RecvExecute(AContext: TIdContext);
var
  recv_stream: TMemoryStream;
  monitors, queue: TList;
  i: Integer;
  screenshot: TScreenshotInfo;
  monitor: TMonitorContext;
begin
  recv_stream := TMemoryStream.Create;
  try
    if not ReceiveStream(AContext, recv_stream) then
    begin
      ROutMsg := AContext.Binding.PeerIP + ' -> receiving failed: ' + IntToStr(recv_Stream.Size) + ' byte';
      Exit;
    end;
    if recv_Stream.Size < 1024 then
    begin
      recv_Stream.Position := 0;
      ROutMsg := AContext.Binding.PeerIP + ' -> captionString received(' + 
                IntToStr(recv_Stream.Size) + ' byte) : "' + StringFromStream(recv_Stream) + '"';
    end
    else
    begin
      ROutMsg := AContext.Binding.PeerIP + ' -> screenshot received: ' + KBStr(recv_Stream.Size) + ' KB';

      monitors := IdTCPServer_Send.Contexts.LockList;
      try
        // alternatively, only queue the screenshot to particular monitors
        // that are actually interested in this client...
        for i := 0 to monitors.Count-1 do
        begin
          monitor := TMonitorContext(monitors[i]);
          screenshot := TScreenshotInfo.Create;
          try
            recv_Stream.Position := 0;
            screenshot.Data.CopyFrom(recv_stream, 0);
            screenshot.Data.Position := 0;
            queue := monitor.Screenshots.LockList;
            try
              queue.Add(screenshot);
              SetEvent(monitor.ScreenshotEvent);
            finally
              monitor.Screenshots.UnlockList;
            end;
          except
            screenshot.Free;
          end;
        end;
      finally
        IdTCPServer_Send.Contexts.UnlockList;
      end;
    end;
  finally
    recv_stream.Free;
  end;
end;

{another side----idTCPServerSend is to send screenshot streams to monitors}

procedure TIndyServerForm.FormCreate(Sender: TObject);
begin
  IdTCPServer_Send.ContextClass := TMonitorContext;
end;

procedure TIndyServerForm.IdTCPServer_SendExecute(AContext: TIdContext);
var
  monitor: TMonitorContext;
  queue: TList;
  i: Integer;
  screenshot: TScreenshotInfo;
begin
  monitor := TMonitorContext(AContext);
  if WaitForSingleObject(monitor.ScreenshotEvent, 1000) <> WAIT_OBJECT_0 then Exit;
  screenshot := nil;
  try
    queue := monitor.Screenshots.LockList;
    try
      if queue.Count > 0 then
      begin
        screenshot := TScreenshotInfo(queue[0]);
        queue.Delete(0);
      end;
      if queue.Count = 0 then
        ResetEvent(monitor.ScreenshotEvent);
    finally
      monitor.Screenshots.UnlockList;
    end;
    if screenshot = nil then Exit;
    // you should send screenshot.ClientIP and screenshot.ClientPort to
    // this monitor so it knows which client the screenshot came from...
    if not SendStream(AContext, screenshot.Data) then
    begin
      SOutMsg := AContext.Binding.PeerIP + ' -> sending failed -> ' + KBStr(screenshot.Data.Size) + ' KB';
      Exit;
    end;
    SOutMsg := AContext.Binding.PeerIP + ' -> sending successful-> ' + KBStr(screenshot.Data.Size) + ' KB';
  finally
    screenshot.Free;
  end;
end;

How should I do? Please give me help.

1
You should upgrade to Indy version >= 10.6. - LU RD
Add IdContext and IdThreadSafe units to your uses list - whosrdaddy
Of course I already added these units. but my units don't inclued above classes. - fangrenxing
It should be clear what you need to do. You need to use a version of Indy that supports this code. - David Heffernan
my purpost is only to keep streams safe between IndyServerthreads - fangrenxing

1 Answers

0
votes

I have found a way without Upgrading Indy version...

Solution is like below..

unit UnitServer;


interface

uses
... ... ...

{$IF Declared(TIdContextThreadList) }
// TIdContextThreadList exists
{$ELSE}
type TIdContextThreadList = TThreadList;
{$IFEND}

{$IF Declared(TIdThreadSafeObjectList) }
// TIdThreadSafeObjectList exists
{$ELSE}
type TIdThreadSafeObjectList = TThreadList;
{$IFEND}

type
  TMonitorContext = class(TIdServerContext)
  public
    Screenshots: TIdThreadSafeObjectList;
    ScreenshotEvent: THandle;
    constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
... ... ...
      ... ... ...

Modified like above and run project,,,, It works well without any problem...

Really Thank you, everyone who gave me advices... And I wanna thank to Mr Remy Lebeau who gave me important guide.