Глубины Indy

       

Пользовательский обработчик IOHandler


Работа Speed Debugger делается на основе пользовательского IOHandler. Маппированый порт  компонент имеет событие OnConnect, и данное событие используется как хук в нашем IOHandler для каждого исходящего клиента, который создает маппированый порт. Это выглядит так:

procedure TformMain.IdMappedPortTCP1Connect(AThread: TIdMappedPortThread);

var

  LClient: TIdTCPConnection;

  LDebugger: TMyDebugger;

begin

  LClient := AThread.OutboundClient;

  LDebugger := TMyDebugger.Create(LClient);

  LDebugger.BytesPerSecond := GSpeed;

  LClient.IOHandler := LDebugger;

end;

Пользовательский класс IOHandler, называется TMyDebugger и реализован как наследник от TIdIOHandlerSocket, являющегося наследником IOHandler. Поскольку TIdIOHandlerSocket уже реализует весь актуальный ввод/вывод, TMyDebugger должен только замедлить передачу данных. Это делается путем перекрытия метода Recv.



Из метода Recv вызывается наследованный Recv для приема данных. Затем, базируясь на выбранном ограничении скорости, рассчитывается необходимая задержка. Если рассчитанная величина больше, чем наследованная, то метод  Recv вызывает Sleep. Это может казаться сложным, но на самом деле это очень просто. Метод  Recv приведен ниже.

function TMyDebugger.Recv(var ABuf; ALen: integer): integer;

var

  LWaitTime: Cardinal;

  LRecvTime: Cardinal;

begin

  if FBytesPerSecond > 0 then

  begin

    LRecvTime := IdGlobal.GetTickCount;

    Result := inherited Recv(ABuf, ALen);

    LRecvTime := GetTickDiff(LRecvTime, IdGlobal.GetTickCount);

    LWaitTime := (Result * 1000) div FBytesPerSecond;

    if LWaitTime > LRecvTime then

    begin

      IdGlobal.Sleep(LWaitTime – LRecvTime);

    end;

  end

  else

  begin

    Result := inherited Recv(ABuf, ALen);

  end;

end;

 



Содержание раздела