英文:
Connected Websocket in Delphi, but no data
问题
以下是您要翻译的代码部分:
unit unitDemoTestWS;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
webSocketClientUnit, Vcl.StdCtrls;
type
TForm1 = class(TForm)
btn1: TButton;
mmo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure btn1Click(Sender: TObject);
private
procedure lSWC1DataEvent(Sender: TObject; const Text: string);
procedure onmyconnected(Sender: Tobject);
{ Private declarations }
public
{ Public declarations }
lSWC: TIdSimpleWebSocketClient;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.lSWC1DataEvent(Sender: TObject; const Text: string);
begin
mmo1.Lines.Add(text);
end;
procedure TForm1.onmyconnected(Sender: Tobject);
begin
mmo1.Lines.Add('We are connected');
end;
procedure TForm1.btn1Click(Sender: TObject);
begin
try
lSWC.Host := '192.168.0.134';
lswc.Port := 55902;
lSWC.Connect;
except
mmo1.Lines.Add('Refused Connect!');
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
try
lSWC := TIdSimpleWebSocketClient.Create(self);
lSWC.onDataEvent := lSWC1DataEvent;
lswc.OnConnected := onmyconnected;
mmo1.Clear;
lSWC.AutoCreateHandler := False;
finally
end;
end;
end.
请注意,我已经移除了代码中的HTML转义字符 '
,以使代码更易于阅读。如果您需要将这些字符还原,请添加它们回到代码中。如果您有任何其他问题或需要进一步的帮助,请随时提出。
英文:
I am making first steps with websockets in a Delphi program, connected to an industrial device.
The device can be connected to using ws://
protocol, and will every second return a 500+/- byte JSON string. This is what I would like to listen to and display in a GUI. I will not have any HTML / JS frontend for this.
I have used the library IdWebsocketSimpleClient, with Delphi 10.4 Community Edition.
I have the following code. It will connect just fine, I get the message about connection. But there is never any data returned. I would have thought that DataEvent
would trigger if any is received.
So what am I missing in order to receive something ? Making feet wet here with D10 for the first time.
I do have F.Piettes / OverByte components installed as well.
unit unitDemoTestWS;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
webSocketClientUnit, Vcl.StdCtrls;
type
TForm1 = class(TForm)
btn1: TButton;
mmo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure btn1Click(Sender: TObject);
private
procedure lSWC1DataEvent(Sender: TObject; const Text: string);
procedure onmyconnected(Sender: Tobject);
{ Private declarations }
public
{ Public declarations }
lSWC:TIdSimpleWebSocketClient;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure Tform1.lSWC1DataEvent(Sender: TObject; const Text: string);
begin
mmo1.Lines.Add(text);
end;
procedure TForm1.onmyconnected(Sender: Tobject);
begin
mmo1.lines.add ('We are connected');
end;
procedure TForm1.btn1Click(Sender: TObject);
begin
try
lSWC.Host := '192.168.0.134';
lswc.Port := 55902;
lSWC.Connect;
except
mmo1.lines.add('Refused Connect!');
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
try
lSWC := TIdSimpleWebSocketClient.Create(self);
lSWC.onDataEvent := lSWC1DataEvent;
lswc.OnConnected := onmyconnected;
mmo1.Clear;
lSWC.AutoCreateHandler := False;
finally
end;
end;
end.
The following Python code works and continously prints the received data - but I would like to display parts of the data using Delphi controls.
from websocket import create_connection
ws = create_connection("ws://192.168.0.134:55902")
while (True):
r = ws.recv()
print (r)
ws.close()
答案1
得分: 2
你没有正确地将TIdSimpleWebSocketClient
连接到服务器。
TIdSimpleWebSocketClient
继承自TIdTCPClient
,它有一个公共的无参数Connect()
方法。你直接调用了TIdTCPClient.Connect()
方法,这只会打开TCP连接,不会执行其他操作。这就是你没有接收到任何数据的原因。
TIdSimpleWebSocketClient
有自己的Connect()
方法(声明为overload
,但实际上应该是reintroduce
,参见此链接),该方法接受WebSocket URL作为输入参数:
procedure Connect(pURL:String);overload;
这是你需要调用的方法,例如:
{lSWC.Host := '192.168.0.134';
lswc.Port := 55902;
lSWC.Connect;}
lSWC.Connect('ws://192.168.0.134:55902');
在内部,TIdSimpleWebSocketClient.Connect()
解析URL以设置Host
和Port
属性,然后连接到服务器,但它还执行了其他几项操作:
- 设置
IOHandler
以启用TLS,如果访问的是安全的WSS URL且AutoCreateHandler
为true。 - 执行WebSocket握手。
- 启动一个工作线程来处理传入数据。
- 启动一个工作线程来处理WebSocket的心跳。
TIdSimpleWebSocketClient.Connect()
的使用甚至在IdWebsocketSimpleClient.pas
的顶部有一个代码示例:
{
示例代码:
//var lSWC:TIdSimpleWebSocketClient;
...
begin
lSWC := TIdSimpleWebSocketClient.Create(self);
lSWC.onDataEvent := self.lSWC1DataEvent; //TSWSCDataEvent
lSWC.AutoCreateHandler := false; //在大多数带有SSL的Websockets中,你可以将其设置为true
if not lSWC.AutoCreateHandler then
begin
if lSWC.IOHandler=nil then
lSWC.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(lSWC);
(lSWC.IOHandler as TIdSSLIOHandlerSocketOpenSSL).SSLOptions.Mode := TIdSSLMode.sslmClient;
(lSWC.IOHandler as TIdSSLIOHandlerSocketOpenSSL).SSLOptions.SSLVersions := [TIdSSLVersion.sslvTLSv1, TIdSSLVersion.sslvTLSv1_1, TIdSSLVersion.sslvTLSv1_2];
end;
lSWC.Connect('wss://echo.websocket.org');
lSWC.writeText('!!It worked!!');
end;
}
话虽如此,你的代码还存在另一个问题。TIdSimpleWebSocketClient.onDataEvent
事件是在工作线程的上下文中触发的,因此在更新Memo时,你的处理程序必须与主UI线程同步,例如:
procedure Tform1.lSWC1DataEvent(Sender: TObject; const Text: string);
begin
TThread.Synchronize(nil, // 或者使用 TThread.Queue()
procedure
begin
mmo1.Lines.Add(text);
end
);
end;
英文:
You are not connecting the TIdSimpleWebSocketClient
to the server correctly.
TIdSimpleWebSocketClient
derives from TIdTCPClient
, which has a public parameter-less Connect()
method. You are calling the TIdTCPClient.Connect()
method directly, which will simply open the TCP connection and do nothing else. That is why you are not receiving any data.
TIdSimpleWebSocketClient
has its own Connect()
method (declared as overload
but it should have been reintroduce
instead), which takes a WebSocket URL as an input parameter:
procedure Connect(pURL:String);overload;
That is the method you need to call instead, eg:
{lSWC.Host := '192.168.0.134';
lswc.Port := 55902;
lSWC.Connect;}
lSWC.Connect('ws://192.168.0.134:55902');
Internally, TIdSimpleWebSocketClient.Connect()
parses the URL to setup the Host
and Port
properties, and then connects to the server, but it also does several other things, too:
- setup the
IOHandler
to enable TLS if accessing a secure WSS url andAutoCreateHandler
is true. - performs the WebSocket handshake.
- starts a worker thread to process incoming data.
- starts a worker thread to handle WebSocket heartbeats.
This use of TIdSimpleWebSocketClient.Connect()
is even demonstrated in a code example located at the very top of IdWebsocketSimpleClient.pas
:
{
Sample code:
//var lSWC:TIdSimpleWebSocketClient;
...
begin
lSWC := TIdSimpleWebSocketClient.Create(self);
lSWC.onDataEvent := self.lSWC1DataEvent; //TSWSCDataEvent
lSWC.AutoCreateHandler := false; //you can set this as true in the majority of Websockets with ssl
if not lSWC.AutoCreateHandler then
begin
if lSWC.IOHandler=nil then
lSWC.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(lSWC);
(lSWC.IOHandler as TIdSSLIOHandlerSocketOpenSSL).SSLOptions.Mode := TIdSSLMode.sslmClient;
(lSWC.IOHandler as TIdSSLIOHandlerSocketOpenSSL).SSLOptions.SSLVersions := [TIdSSLVersion.sslvTLSv1, TIdSSLVersion.sslvTLSv1_1, TIdSSLVersion.sslvTLSv1_2];
end;
lSWC.Connect('wss://echo.websocket.org');
lSWC.writeText('!!It worked!!');
end;
}
That being said, there is another issue with your code. The TIdSimpleWebSocketClient.onDataEvent
event is triggered in the context of a worker thread, so your handler must synchronize with the main UI thread when updating your Memo, eg:
procedure Tform1.lSWC1DataEvent(Sender: TObject; const Text: string);
begin
TThread.Synchronize(nil, // or TThread.Queue()
procedure
begin
mmo1.Lines.Add(text);
end
);
end;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论