Delphi 10.4: Indy TIdTCPClient, считывающий данные из веб-сокета и веб-сервера

Я пытаюсь читать данные в реальном времени, отправляемые с сервера каждые 4 мс. Я использую TCPclinet в Delphi 10.4 и Indy 10 для кроссплатформенного приложения. Все коммуникации между клиентом и сервером основаны на тексте и HTML. На сервере работает веб-сервер (порт 80) и веб-сокет (порт 81). Сервер показывает страницу, которая ожидает отправки 1, а затем начинает отправку данных через сокет. Это работает в TwebBrowser1, и я вижу данные. Я также протестировал свой веб-сокет, используя расширение Chrome, и, похоже, он отправляет данные, как ожидалось (https://chrome.google.com/webstore/detail/websocket-test-client/fgponpodhbmadfljofbimhhlengambbn?hl=en). Однако я не получаю никаких данных в моем сокете на клиенте, используя приведенный ниже код на основе ссылок здесь Delphi: Indy TIdTCPClient для чтения данных и редактирования Реми, а также его обновления здесь https://en.delphipraxis.net/topic/1010-using-indy-for-cross-platform-tcpip/. Также, чтобы получить структуру потока, я использовал здесь ответ Реми Indy TIdTCPClient для получения текста. Исправлен код на основе большего количества чтения, чтобы не вызывать основную угрозу пользовательского интерфейса для ответа на отладочное чтение.

Любая помощь в том, где я ошибаюсь, будет очень признательна.

unit Mainunit;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types,
  FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo
  ,IdCustomTransparentProxy, IdSocks, IdBaseComponent,
  IdComponent, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack,
  IdTCPConnection, IdTCPClient, IdSync, FMX.WebBrowser
  ,Web.HTTPApp, IdHTTP;

type

  TDataEvent = procedure(const Data: string) of object;

  TReadingThread = class(TThread)
    private
      FClient : TIdTCPClient;
      Fdata: string;
      FOnData: TDataEvent;
      procedure DataReceived;
    protected
      procedure Execute; override;
      procedure DoTerminate; override;
    public
      constructor Create(AClient: TIdTCPClient); reintroduce;
      property OnData: TDataEvent read FOnData write FOnData;
    end;

  TLog = class(TIdSync)
  protected
    FMsg: String;
    procedure DoSynchronize; override;
  public
    constructor Create(const AMsg: String);
    class procedure AddMsg(const AMsg: String);
  end;

  TMainForm = class(TForm)
    Memo1: TMemo;
    Connect_btn: TButton;
    IdTCPClient1: TIdTCPClient;
    Disconnect_btn: TButton;
    WebBrowser1: TWebBrowser;
    refresh_btn: TButton;

    procedure DataReceived(const Data: string);
    procedure CreateTCPIPConnection;
    procedure Connect_btnClick(Sender: TObject);
    procedure Disconnect_btnClick(Sender: TObject);
    procedure refresh_btnClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);

  private
    { Private declarations }
  public
    { Public declarations }
    request_count : integer;

  end;

var
  MainForm: TMainForm;
  ZPReadThread: TReadingThread = nil;

implementation

{$R *.fmx}


procedure TMainForm.CreateTCPIPConnection;
begin
  if not Assigned(ZPReadThread) then
  begin
    IdTCPClient1.Host := '192.168.11.5';
    IdTCPClient1.Port := 81;
    try
      ZPReadThread := TReadingThread.Create(IdTCPClient1);
      try
        ZPReadThread.OnData := DataReceived;
        ZPReadThread.Start;
      except
        FreeAndNil(ZPReadThread);
        raise;
      end;
    except
      on E: Exception do
      begin
        TLog.AddMsg('DEBUG: TCP/IP exception creating read thread : '+E.Message);
       end;
    end;
  end;
end;



constructor TReadingThread.Create(AClient: TIdTCPClient);
begin
  TLog.AddMsg('DEBUG: TReadingThread.Create');
  inherited Create(True);
  FClient := AClient;
end;


procedure TReadingThread.Execute;
begin
  try
    FClient.ConnectTimeout := 10000; // <-- use whatever you want...   was 10000
    FClient.Connect;
    if FClient.Connected then
      TLog.AddMsg('DEBUG: Threat execute connected to the client: ' + FClient.Host
                  + '   on port: '        + inttostr(FClient.Port)
                  + '   RecvBufferSize: ' + inttostr(FClient.IOHandler.RecvBufferSize)
                  );
  except
    on E: Exception do
    begin
      TLog.AddMsg('DEBUG: TCP/IP connect exception : '+E.Message);
      raise;
    end;
  end;

  try
    FClient.IOHandler.ReadTimeout := 1000; // <-- use whatever you want...  was 5000
    while not Terminated do
    begin
      try
        FData := FClient.IOHandler.ReadLn();
      except
        on E: Exception do
        begin
            TLog.AddMsg('DEBUG: TCP/IP IOHandler.ReadLn exception : '+E.Message);
          raise;
        end;
      end;
       //  if (FData <> '') and Assigned(FOnData) then Synchronize(DataReceived);
        Synchronize(DataReceived);
        SetLength (FData,0);
    end;
  finally
    FClient.Disconnect;
  end;
end;


procedure TReadingThread.DataReceived;
begin
  if Assigned(FOnData) then FOnData(FData);
   Mainform.request_count :=  Mainform.request_count + 1;
   TLog.AddMsg('Debug: ' +  inttostr(MainForm.request_count)+ ' ) Inside proc DataRecieved of thread fdata is: ' + FData);
end;


procedure TReadingThread.DoTerminate;
begin
  TLog.AddMsg('Debug: Read thread terminating');
  inherited;
end;

constructor TLog.Create(const AMsg: String);
begin
  inherited Create;
  FMsg := AMsg;
end;

procedure TLog.DoSynchronize;
begin
  Mainform.Memo1.Lines.Add(FMsg);
end;

class procedure TLog.AddMsg(const AMsg: String);
begin
  with Create(AMsg) do
  try
    Synchronize;
  finally
    Free;
  end;
end;



procedure TMainForm.DataReceived(const Data: string);
begin
  Memo1.Lines.Add('Recevied data DataRecieved of form : ' + Data);
end;

procedure TMainForm.Connect_btnClick(Sender: TObject);

begin
  try
    WebBrowser1.Navigate('http://192.168.11.5/');
    CreateTCPIPConnection();
    request_count := 0;

  except
    on E: Exception do
      MainForm.Memo1.Lines.Add('Threat connection Error: ' + E.Message);
    end;
  end;


procedure TMainForm.Disconnect_btnClick(Sender: TObject);
begin
  if Assigned(ZPReadThread) then
  begin
    TLog.AddMsg('Debug: Terminating Read thread');
    ZPReadThread.Terminate;
    TLog.AddMsg('Debug:Waiting for read thread termination');
    ZPReadThread.WaitFor;
    TLog.AddMsg('Debug:Finished waiting for read thread termination');
    FreeAndNil(ZPReadThread);
  end
  else TLog.AddMsg('Debug:Thread not active');
end;



procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   Disconnect_btnClick(Sender);
end;

procedure TMainForm.refresh_btnClick(Sender: TObject);
begin
    WebBrowser1.Reload;
    memo1.Lines.clear;
    request_count := 0;
end;


end.

person na38    schedule 26.02.2021    source источник


Ответы (1)


Отвечая на свой вопрос выше, если это поможет другим. Кто-то поправит меня, если я ошибаюсь, но нет возможности использовать базовый TidTCPClient для чтения данных из веб-сокета. Однако существует клиент WebSocket, унаследованный от TIdTCPClient (https://github.com/arvanus/Indy/blob/WebSocketImpl/Lib/Core/IdWebSocketSimpleClient.pas), который отлично работает. Я смог подключиться к моему сокету, и все, что мне нужно было добавить, это процедура для чтения данных.

person na38    schedule 08.03.2021