Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi程序内如何等待套接字应答?_Delphi_Sockets_Delphi Xe2 - Fatal编程技术网

Delphi程序内如何等待套接字应答?

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

对于某些特定需要,我需要创建在dll中等待套接字请求或应答的过程:

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,所以我接受你的答案。