Indy 10 IdTCPClient 使用单独的线程读取数据?
问题:我正在寻找的是在 Indy 10 中使用单独线程通过 IdTCPClient 接收数据的最典型或最佳实践方法。
背景: 下面的代码是我尝试执行的示例,为了清楚起见,删除了实际的数据处理部分。 线程的想法是接收所有数据(可变大小,带有声明消息其余长度的标头),然后解析它(这就是 HandleData 过程的作用)并根据命令触发事件处理程序。
TIdIOHandlerSocket 由主应用程序传递给线程,主应用程序还会在需要时将数据写入套接字。
TScktReceiveThread = class(TThread)
private
{ Private declarations }
procedure HandleData;
protected
procedure Execute; override;
public
FSocket: TIdIOHandlerSocket;
constructor Create(CreateSuspended: boolean);
end;
procedure TScktReceiveThread.Execute;
var
FixedHeader: TBytes;
begin
Assert(FSocket <> nil, 'You must assign the connected socket to the receiving thread');
SetLength(FixedHeader, 2);
while not Terminated do
begin
if not FSocket.Connected then
Suspend
else
begin
FSocket.CheckForDataOnSource(10);
if not FSocket.InputBufferIsEmpty then
begin
FSocket.ReadBytes(FixedHeader, SizeOf(FixedHeader), false);
// Removed the rest of the reading and parsing code for clarity
Synchronize(HandleData);
end;
end;
end;
end;
作为前缀,我使用了另一个处理 Indy 服务器组件的 StackOverflow 问题:“Delphi 2009,Indy 10,TIdTCPServer.OnExecute,如何抓取InputBuffer中的所有字节”以获得我所拥有的基础迄今为止。
谢谢你的帮助!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您想避免为每个客户端-服务器数据交换创建线程类所带来的开销,您可以创建一个移动线程类,如
http://delphidicas.blogspot.com/2008/08/anonymous-methods-when-should-they-be.html
几天前我遇到了同样的问题,我刚刚写了一个类 TMotileThreading,它具有静态函数,可以让我使用 D2009 的新匿名方法功能创建线程。 看起来像这样:
第二个过程允许我像您的情况一样执行客户端-服务器通信,并在数据到达时执行一些操作。 匿名方法的好处是您可以使用调用上下文的局部变量。 因此,通信看起来像这样:
Execute 和 ExecuteThenCall 方法只是创建一个工作线程,将 FreeOnTerminate 设置为 true 以简化内存管理,并执行工作线程的 Execute 和 OnTerminate 过程中提供的函数。
希望有帮助。
编辑(根据要求,TMotileThreading 类的完整实现)
If you want to avoid the overhead imposed by creating thread classes for each and every client-server data exchange, you could create a motile threading class as described in
http://delphidicas.blogspot.com/2008/08/anonymous-methods-when-should-they-be.html
I had the same problem a few days ago and I just wrote me a class TMotileThreading which has static functions that let me create threads using the new anonymous method feature of D2009. Looks something like this:
The second procedure allows me to perform a client-server communication like in your case and do some stuff whenever the data has arrived. The nice thing about anonymous methods is that you can use the local variables of the calling context. So a communication looks something like this:
The Execute and ExecuteThenCall method simply create a worker thread, set FreeOnTerminate to true to simplify memory management and execute the provided functions in the worker thread's Execute and OnTerminate procedures.
Hope that helps.
EDIT (as requested the full implementation of class TMotileThreading)
你走在正确的轨道上。 Indy 就是打算这样使用的。 它使用阻塞套接字,因此
ReadBytes
调用在读取您所请求的内容之前不会返回。 与非阻塞套接字相比,在非阻塞套接字中,调用可能会提前返回,因此您可以异步轮询或收到通知来确定请求何时已被填充。Indy 的设计预期套接字对象拥有自己的线程(或纤程)。 Indy 附带了
TIdAntifreeze
,适合那些想要将套接字组件拖放到其表单和数据模块上并从主 GUI 线程使用 Indy 组件的人们,但如果您可以避免的话,这通常不是一个好主意它。由于如果没有分配
FSocket
,您的线程就无法工作,因此我建议您只需在类的构造函数中接收该值即可。 如果未分配,则在构造函数中断言。 此外,创建非挂起线程是一个错误,那么为什么还要给出这个选项呢? (如果创建的线程没有挂起,那么它将开始运行,检查FSocket
是否已分配,并失败,因为创建线程尚未分配该字段。)You're on the right track. Indy is intended to be used like that. It uses blocking sockets, so the
ReadBytes
call doesn't return until it's read what you've asked for. Contrast that with non-blocking sockets, where a call may return early, so you either poll or get notified asynchronously to determine when a request has been filled.Indy is designed with the expectation that the socket objects have their own threads (or fibers). Indy comes with
TIdAntifreeze
for the folks who want to drag and drop socket components onto their forms and data modules and use the Indy components from the main GUI thread, but that's not generally a good idea if you can avoid it.Since your thread cannot work without
FSocket
being assigned, I advise you to simply receive that value in the class's constructor. Assert in the constructor if it's not assigned. Furthermore, it is an error to create your thread non-suspended, so why even give the option? (If the thread is not created suspended, then it will start running, check whetherFSocket
is assigned, and fail because the creating thread hasn't gotten to assign that field yet.)