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

时间:2012-07-02 13:46:26

标签: 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 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;

2 个答案:

答案 0 :(得分:4)

默认情况下,

TServerSocket以非阻塞模式运行,这取决于处理窗口消息。要删除该依赖性,您必须将其切换为阻止模式。

TIdTCPServer专门以阻塞模式运行,因此没有窗口消息。如果您遇到问题,那么您就是在滥用它。例如,在您的TServerSocket代码中,在收到回复之前,您不会设置Go = True,而是在您的TServerSocket代码中设置Go = True,然后才能阅读回复代替。

作为替代方案,请查看Indy的TIdSimpleServer组件。 TIdSimpleServer是同步的,一次只接受1个连接,而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; 

答案 1 :(得分:1)

不是创建偶尔调用Application.ProcessMessages的循环,而是可以创建TThread的后代并将套接字请求移动到TThread.Execute方法。使用TThread.OnTerminate在线程完成其工作时通知您的表单(或任何其他类)。

sample code提供了有关如何使用TThread的详细信息。

还有其他几个3rd party线程库比TThread提供更多的灵活性或更易于使用,如果您不熟悉多个TThread,我强烈推荐其中任何一个-threading。

注意:使用Application.ProcessMessages时有一些严重side-effects。您正在使用dll解锁应用程序的mainform,在代码中看到其中一个。它打破了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以便可以从线程中检索数据财产。