Delphi程序内如何等待套接字应答?
对于某些特定需要,我需要创建在dll中等待套接字请求或应答的过程:Delphi程序内如何等待套接字应答?,delphi,sockets,delphi-xe2,Delphi,Sockets,Delphi Xe2,对于某些特定需要,我需要创建在dll中等待套接字请求或应答的过程: TForm1 = class(TForm) ServerSocket1: TServerSocket; ...... procedure MyWaitProc; stdcall; begin Go := false; while not Go do begin // Wating... // Application.ProcessMessages; // Works with this
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
......
procedure MyWaitProc; stdcall;
begin
Go := false;
while not Go do
begin
// Wating...
// Application.ProcessMessages; // Works with this line
end;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
MessageBoxA(0, PAnsiChar('Received: '+Socket.ReceiveText), '', MB_OK);
Go := true;
end;
exports
MyWaitProc;
当我调用Application.ProcessMessages时,一切正常:应用程序等待请求,然后继续。但在我的例子中,调用Application.ProcessMessages会导致解锁主机应用程序上的主窗体,而不是dll的窗体。当我不调用Application.ProcessMessages应用程序时,它只是挂起,因为它无法处理消息
那么,如何创建这样一个等待套接字应答的过程呢?
是否有一种方法可以在不使用Application.ProcessMessages的情况下等待套接字应答
编辑
我还尝试使用TIdTCPServer,由于某些原因,结果是一样的
TForm1 = class(TForm)
IdTCPServer1: TIdTCPServer;
.....
procedure MyWaitProc; stdcall;
begin
Go := false;
while not Go do
begin
// Waiting ...
// Application.ProcessMessages;
end;
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
s: string;
begin
s := AContext.Connection.Socket.ReadString(1);
AllText := AllText + s;
Go := True;
end;
您可以创建TThread的子代并将套接字请求移动到TThread.Execute方法,而不是创建偶尔调用Application.ProcessMessages的循环。当线程完成其工作时,使用TThread.OnTerminate通知窗体或任何其他类 有一个示例提供了有关如何使用TThread的更多详细信息 还有其他几个线程库,它们要么比TThread提供更大的灵活性,要么更易于使用。如果您是多线程新手,我强烈推荐它们中的任何一个,而不是TThread 注意:使用Application.ProcessMessages存在一些严重问题。通过dll解锁应用程序的主窗体,您可以在代码中看到其中一个。它打破了VCL构建的单线程UI模型。ProcessMessages有它的位置,但是使用线程更适合您所描述的情况
var Slowpoke: TMyLongRunningProcessThread;
procedure MyWaitProc(Completed:TNotifyEvent)
begin
Slowpoke := TMyLongRunningProcessThread.Create(True);
Slowpoke.FreeOnTerminate := True;
Slowpoke.OnTerminate := Completed;
Slowpoke.Resume;
end;
MyWaitProc在启动线程后立即返回,因此GUI可以自由响应用户操作。当线程终止时,它调用Completed所指向的事件处理程序
显然,如果您需要从线程检索数据,您需要在线程释放自身之前将其写入可访问的内存位置,或者删除FreeOnTerminate,以便通过属性从线程检索数据。而不是创建偶尔调用Application.ProcessMessages的循环,您可以创建TThread的子代并将套接字请求移动到TThread.Execute方法。当线程完成其工作时,使用TThread.OnTerminate通知窗体或任何其他类 有一个示例提供了有关如何使用TThread的更多详细信息 还有其他几个线程库,它们要么比TThread提供更大的灵活性,要么更易于使用。如果您是多线程新手,我强烈推荐它们中的任何一个,而不是TThread 注意:使用Application.ProcessMessages存在一些严重问题。通过dll解锁应用程序的主窗体,您可以在代码中看到其中一个。它打破了VCL构建的单线程UI模型。ProcessMessages有它的位置,但是使用线程更适合您所描述的情况
var Slowpoke: TMyLongRunningProcessThread;
procedure MyWaitProc(Completed:TNotifyEvent)
begin
Slowpoke := TMyLongRunningProcessThread.Create(True);
Slowpoke.FreeOnTerminate := True;
Slowpoke.OnTerminate := Completed;
Slowpoke.Resume;
end;
MyWaitProc在启动线程后立即返回,因此GUI可以自由响应用户操作。当线程终止时,它调用Completed所指向的事件处理程序
显然,如果您需要从线程检索数据,您需要在线程释放自身之前将其写入可访问的内存位置,或者删除FreeOnTerminate,以便通过属性从线程检索数据。TServerSocket默认情况下以非阻塞模式运行,这取决于处理窗口消息。要消除这种依赖性,您必须将其切换到阻塞模式
TIdTCPServer以独占方式在阻塞模式下运行,因此没有窗口消息。如果你对它有问题,那么你就是在滥用它。例如,在TServerSocket代码中,只有在收到响应后才设置Go=True,但在TServerSocket代码中,在读取响应之前才设置Go=True
另外,请看一看Indy的TIdSimpleServer组件。TIdSimpleServer是同步的,一次只接受一个连接,而TIdTCPServer是异步的,一次接受多个连接。例如:
TForm1 = class(TForm)
ServerSocket: TIdSimpleServer;
procedure MyWaitProc; stdcall;
var
s: String;
begin
ServerSocket.Listen;
s := ServerSocket.IOHandler.ReadLn;
ServerSocket.Disconnect;
MessageBox(0, PChar('Received: '+s), '', MB_OK);
end;
exports
MyWaitProc;
TServerSocket默认以非阻塞模式运行,这取决于处理窗口消息。要消除这种依赖性,您必须将其切换到阻塞模式
TIdTCPServer以独占方式在阻塞模式下运行,因此没有窗口消息。如果你对它有问题,那么你就是在滥用它。例如,在TServerSocket代码中,只有在收到响应后才设置Go=True,但在TServerSocket代码中,在读取响应之前才设置Go=True
另外,请看一看Indy的TIdSimpleServer组件。TIdSimpleServer是同步的,一次只接受一个连接,而TIdTCPServer是异步的,一次接受多个连接。例如:
TForm1 = class(TForm)
ServerSocket: TIdSimpleServer;
procedure MyWaitProc; stdcall;
var
s: String;
begin
ServerSocket.Listen;
s := ServerSocket.IOHandler.ReadLn;
ServerSocket.Disconnect;
MessageBox(0, PChar('Received: '+s), '', MB_OK);
end;
exports
MyWaitProc;
我建议使用b
锁定库(如Indy或Synapse)以执行此任务,因为TServerSocket使用Windows事件循环,这使得在DLL应用程序中很难使用。@mjn,我尝试使用IdTCPServer,但结果是一样的。它还使用windows消息调用OneExecute事件…IdTCPServer不使用windows消息,它基于windows Winsock API。OnExecute是在客户端连接的主循环中调用的,而不是在Windows消息循环中调用的。@mjn,编辑了我的帖子。即使使用TIdTCPServer,我仍然无法工作。在DLL或主应用程序中,TForm1的表单实例在哪里创建,TCP服务器在哪里运行?我建议使用像Indy或Synapse这样的阻塞库来完成此任务,因为TServerSocket使用Windows事件循环,这使得在DLL应用程序中很难使用。@mjn,我尝试使用IdTCPServer,但结果是一样的。它还使用windows消息调用OneExecute事件…IdTCPServer不使用windows消息,它基于windows Winsock API。OnExecute是在客户端连接的主循环中调用的,而不是在Windows消息循环中调用的。@mjn,编辑了我的帖子。即使使用TIdTCPServer,我仍然无法工作。在DLL或主应用程序中,TForm1的表单实例在哪里创建,TCP服务器在哪里运行?Kenneth,我不确定我是否理解你的意思,在我的DLL中,哪一个调用我将移动到线程?如果我的dll根本没有表单,我该如何通知表单呢?Kenneth,我知道如何使用TThread thanx作为示例,但我仍然不明白它如何解决我的问题…Ken,thanx作为答案。但我需要我的过程在收到套接字的请求之前不要结束。这似乎很奇怪,但这正是我需要的。。。我真的需要在等待时锁定我的GUI。当我在单独的线程中停止使用TIdSimpleThread时,我投票赞成你的线程化想法。Thanx:我不确定我是否理解你的意思,Kenneth,在我的dll中,哪一个调用我要移动到一个线程?如果我的dll根本没有表单,我该如何通知表单呢?Kenneth,我知道如何使用TThread thanx作为示例,但我仍然不明白它如何解决我的问题…Ken,thanx作为答案。但我需要我的过程在收到套接字的请求之前不要结束。这似乎很奇怪,但这正是我需要的。。。我真的需要在等待时锁定我的GUI。当我在单独的线程中停止使用TIdSimpleThread时,我投票赞成你的线程化想法。塔克斯:塔克斯,雷米。但在我的例子中,我需要异步性和等待响应的能力。我认为同步组件无法解决我的问题,因为dll中的其他函数是异步工作的……而且我需要不止一个连接。然后需要一种方法告诉MyWaitProc它必须等待哪个连接。然后你需要修复我之前指出的错误,Go设置为True太快了。现在我停止在单独的线程中使用TIdSimpleServer,所以我接受你的答案。Thanx,Remy。但在我的例子中,我需要异步性和等待响应的能力。我认为同步组件无法解决我的问题,因为dll中的其他函数是异步工作的……而且我需要不止一个连接。然后需要一种方法告诉MyWaitProc它必须等待哪个连接。然后你需要修复我前面指出的错误,因为Go设置为True的时间太快了。现在我停止在单独的线程中使用TIdSimpleServer,所以我接受你的答案。