问题描述
我正在尝试读取每 4 毫秒从服务器发送的实时数据。我在 Delphi 10.4 和 Indy 10 中使用 TCPclinet 作为跨平台应用程序。客户端和服务器之间的所有通信都是基于文本和 html 的。服务器正在运行一个 web 服务器(端口 80)和一个 websocket(端口 81)。服务器显示一个页面,等待发送 1,然后开始通过套接字发送数据。这在 Twebbrowser1 中有效,我看到了数据。我还使用 chrome 扩展测试了我的 websocket,它似乎按预期发送数据 (https://chrome.google.com/webstore/detail/websocket-test-client/fgponpodhbmadfljofbimhhlengambbn?hl=en)。但是,我没有使用以下代码在客户端的套接字中获取任何数据,这些代码基于 Delphi: Indy TIdTCPClient Reading Data 处的链接和 Remy 的编辑以及 https://en.delphipraxis.net/topic/1010-using-indy-for-cross-platform-tcpip/ 处的更新。同样为了获得线程结构,我在这里使用了 Remy 的答案 Indy TIdTCPClient receive text。基于更多阅读清理代码,以免调用主 UI 威胁进行调试阅读响应。
对我哪里出错的任何帮助将不胜感激。
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.
解决方法
在上面回答我自己的问题,以防对其他人有帮助。如果我错了,有人会纠正我,但无法使用基本的 TidTCPClient 从 websocket 读取数据。但是,从 TIdTCPClient (https://github.com/arvanus/Indy/blob/WebSocketImpl/Lib/Core/IdWebSocketSimpleClient.pas) 继承的 WebSocket 客户端效果很好。我能够连接到我的套接字,我需要添加的只是一个读取数据的过程。