- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是 Delphi 的新手,我正在尝试进行一些网络操作。在本例中,我想连接到(我们称之为)通知服务器,该服务器将在发生某些事件时发送字符串。
我的第一个方法是这样的:我在自己的线程上运行 TIdTCPClient 并设置 ReadTimeout,这样我就不会总是被阻塞。这样我就可以检查线程的终止状态。
ConnectionToServer.ReadTimeout := MyTimeOut;
while( Continue ) do
begin
//
try
Command := ConnectionToServer.ReadLn( );
except
on E: EIdReadTimeout do
begin
//AnotarMensaje(odDepurar, 'Timeout ' + E.Message );
end;
on E: EIdConnClosedGracefully do
begin
AnotarMensaje(odDepurar, 'Conexión cerrada ' + E.Message );
Continue := false;
end;
on E: Exception do
begin
AnotarMensaje(odDepurar, 'Error en lectura ' + E.Message );
Continue := false;
end;
end;
// treat the command
ExecuteRemoteCommand( Command );
if( self.Terminated ) then
begin
Continue := false;
end;
end; // while continue
阅读 ReadLn 代码,我发现它在重复直到循环中进行一些主动等待,始终检查某些缓冲区大小。
有没有办法以 TIdTCPServer 与 OnExecute 等方法一起工作的方式异步执行此操作?或者,至少,有某种方法可以避免这种主动等待。
最佳答案
Indy 在客户端和服务器端都使用阻塞套接字。它没有什么异步的地方。以TIdTCPServer
为例,它在单独的工作线程中运行每个客户端套接字,就像您尝试在客户端中执行的操作一样。 TIdTCPClient
1 不是多线程,因此您必须运行自己的线程。
1:如果您升级到 Indy 10,它会有 TIdCmdTCPClient
多线程客户端,为您运行自己的线程,触发 TIdCommandHandler.OnCommand
从服务器接收到的数据包的事件。
ReadLn()
运行循环直到指定的 ATerminator
可以在 InputBuffer
中找到,或者直到发生超时。直到ATerminator
发现,ReadLn()
从套接字读取更多数据到 InputBuffer
并再次扫描。缓冲区大小检查只是为了确保它不会重新扫描已经扫描过的数据。
“唤醒”阻塞的唯一方法ReadLn()
调用(或任何阻塞套接字调用,就此而言)是从另一个线程关闭套接字。否则,你只需等待调用正常超时即可。
另请注意 ReadLn()
不提出 EIdReadTimeout
超时时异常。它设置 ReadLnTimedout
属性设置为True,然后返回一个空字符串,例如:
ConnectionToServer.ReadTimeout := MyTimeOut;
while not Terminated do
begin
try
Command := ConnectionToServer.ReadLn;
except
on E: Exception do
begin
if E is EIdConnClosedGracefully then
AnotarMensaje(odDepurar, 'Conexión cerrada')
else
AnotarMensaje(odDepurar, 'Error en lectura: ' + E.Message );
Exit;
end;
end;
if ConnectionToServer.ReadLnTimedout then begin
//AnotarMensaje(odDepurar, 'Timeout');
Continue;
end;
// treat the command
ExecuteRemoteCommand( Command );
end;
如果你不喜欢这个模型,你不必使用Indy。更高效、响应更快的模型是直接使用 WinSock。您可以将重叠 I/O 与 WSARecv()
一起使用,并通过 CreateEvent()
创建一个等待事件或 TEvent
来发出线程终止信号,然后您的线程可以使用 WaitForMultipleObjects()
当无事可做时,在 sleep 时同时等待套接字和终止,例如:
hSocket = socket(...);
connect(hSocket, ...);
hTermEvent := CreateEvent(nil, True, False, nil);
...
var
buffer: array[0..1023] of AnsiChar;
wb: WSABUF;
nRecv, nFlags: DWORD;
ov: WSAOVERLAPPED;
h: array[0..1] of THandle;
Command: string;
Data, Chunk: AnsiString;
I, J: Integer;
begin
ZeroMemory(@ov, sizeof(ov));
ov.hEvent := CreateEvent(nil, True, False, nil);
try
h[0] := ov.hEvent;
h[1] := hTermEvent;
try
while not Terminated do
begin
wb.len := sizeof(buffer);
wb.buf := buffer;
nFlags := 0;
if WSARecv(hSocket, @wb, 1, @nRecv, @nFlags, @ov, nil) = SOCKET_ERROR then
begin
if WSAGetLastError() <> WSA_IO_PENDING then
RaiseLastOSError;
end;
case WaitForMultipleObjects(2, PWOHandleArray(@h), False, INFINITE) of
WAIT_OBJECT_0: begin
if not WSAGetOverlappedResult(hSocket, @ov, @nRecv, True, @nFlags) then
RaiseLastOSError;
if nRecv = 0 then
begin
AnotarMensaje(odDepurar, 'Conexión cerrada');
Exit;
end;
I := Length(Data);
SetLength(Data, I + nRecv);
Move(buffer, Data[I], nRecv);
I := Pos(Data, #10);
while I <> 0 do
begin
J := I;
if (J > 1) and (Data[J-1] = #13) then
Dec(J);
Command := Copy(Data, 1, J-1);
Delete(Data, 1, I);
ExecuteRemoteCommand( Command );
end;
end;
WAIT_OBJECT_0+1: begin
Exit;
end;
WAIT_FAILED: begin
RaiseLastOSError;
end;
end;
end;
except
on E: Exception do
begin
AnotarMensaje(odDepurar, 'Error en lectura ' + E.Message );
end;
end;
finally
CloseHandle(ov.hEvent);
end;
end;
如果您使用的是 Delphi XE2 或更高版本,TThread
有虚拟TerminatedSet()
您可以覆盖信号 hTermEvent
的方法当TThread.Terminate()
叫做。否则,只需调用 SetEvent()
调用Terminate()
后.
关于delphi - 使用 TIdTCPClient 异步读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44196849/
我们有一个使用 INDY 的 Delphi 客户端服务器应用程序。客户端与服务器的单个 tIdTCPClient 连接是多线程的。客户端“理论上”是一个单线程。但实际上客户端上有多个线程,这就是我的问
我想知道是否有办法以某种方式 ping 或发送一个空请求,以便使用 TIdTCPClient 查看来自给定服务器的响应(以及响应时间)。在德尔福 - 我尝试的是这样的: TCPClient := TI
我正在处理一个需要在连接和握手后启动 TLS 的协议(protocol),如下所示: procedure TForm1.Button1Click(Sender: TObject); var SSL
我是 Delphi 的新手,我正在尝试进行一些网络操作。在本例中,我想连接到(我们称之为)通知服务器,该服务器将在发生某些事件时发送字符串。 我的第一个方法是这样的:我在自己的线程上运行 TIdTCP
在互联网上,我看到通常将“TIdTCPClient”放置在自定义 TThread 后代中......为什么要这样做? 有时我也会在这样的线程中看到服务器...为什么? 干杯,阿德里安 最佳答案 Ind
我正在使用 Delphi 10 Seattle 使用 TIdTCPClient 和 TIdTCPServer 组件构建一个简单的客户端/服务器应用程序。 为了读取从服务器应用程序 (TIdTCPSer
当我使用 TIdTCPClient 组件连接到 80 端口、纯文本网站时,一切正常,接收数据没有问题,但是,当我连接到 443 端口、SSL 网站时,数据并不总是来了。 也许我的接收数据 block
如何使用 TIdTcpClient 接收具有以下条件的 100 字节字符串?: 如果没有任何进来,Read 调用将被阻塞,线程将永远等待 如果收到 100 个字节,Read 调用应返回字节字符串 如果
我的客户端接收字符串,其中字符串的前 4 个字符定义消息的长度。 示例字符串:0034PDCS00001700kg00000000kg00001700kg 消息长度为34 消息是PDCS0000170
我正在使用 Delphi 2007 和 Indy 10;我是一个德尔福菜鸟,所以如果我错过了一些明显的东西,我深表歉意...... 背景:我有一个简单的服务器应用程序,当您连接到其端口时,它只是发送“
我需要帮助来了解如何通过 Indy TCP 服务器/客户端传输记录。我有两个程序,一个是客户端,另一个是服务器。在客户端上的按钮上我放置了连接:客户端是 TIdTCPClient Client.Con
我正在使用 Internet Direct TIdTCPClient 组件与远程服务通信以检索通常大小约为 5k 的消息。在典型的操作中,我将向服务发送大约 400 个请求,每个请求大约需要 1 秒才
是否可以使用 同时发送/接收大型流? TIdTCPServer/TIdTCPClient 与同一个客户。 我在客户端创建了一个线程来处理传入的请求。 客户端收到请求,但在前一个请求完成(发送或接收)之
我不确定 Delphi 何时创建主窗体的子组件。 在我的 TMainForm.FormCreate() 中,我正在调用 TIdTCPClient.Connect() 和 TIdTCPClient.Se
我正在 Delphi 中使用 TIdTCPClient/TIdTcpServer indy 组件编写客户端-服务器应用程序。 数据传输通常工作正常,但我经常从服务器读取错误的数据;我得到了以前请求的答
我正在使用 Delphi xe6 来实现一个简单的客户端/服务器连接。客户端表单应该有一个 TEdit 组件,并且应该将 Edit.text 字符串发送到服务器备忘录。我想使用 Indy 组件:TId
我有一个使用 TIdTCPClient 从给定网站发送和接收数据的应用程序 - 如下所示: TCPClient.Host := myHost; TCPClient.Port := myPort; TC
我有一个简单的 TidTCPServer 在控制台上工作并接受数据。我的问题是当客户端发送流但交换数据的速度非常快时,服务器在 70 行后卡住,服务器的 CPU 负载达到 70%;我不知道如何在每次发
我正在使用 Delphi 10.2 并构建一个移动应用程序 我的任务之一是将图像从移动设备发送到服务器 我从 stackoverflow 获得了一个代码来执行此操作并运行它,但它不起作用 服务器端代码
我正在尝试一些 IP PBX 系统(Asterisk、Freeswitch 和 Yate)来注册 PBX 中的事件,我想知道这些组件中哪一个更好。 该组件应该向 PBX 注册事件、接收事件、发送一些响
我是一名优秀的程序员,十分优秀!