Delphi2010的Indy全接触之UDP篇

首先新建服务端。

  如下图所示建立工程:

Delphi2010的Indy全接触之UDP篇_第1张图片
代码如下:

unitServerUnit;
interface
uses
 Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
 Dialogs,IdBaseComponent,IdComponent,IdUDPBase,IdUDPServer,StdCtrls,
 IdSocketHandle,IdGlobal;
type
 TServerForm=class(TForm)
  Label1:TLabel;
  Edit1:TEdit;
  Label2:TLabel;
  Edit2:TEdit;
  Label3:TLabel;
  Edit3:TEdit;
  IdUDPServer1:TIdUDPServer;
  procedureIdUDPServer1UDPRead(AThread:TIdUDPListenerThread;AData:TBytes;
   ABinding:TIdSocketHandle);
  procedureFormCreate(Sender:TObject);
 private
  {Privatedeclarations}
 public
  {Publicdeclarations}
 end;
var
 ServerForm:TServerForm;
implementation
{$R*.dfm}
procedureTServerForm.FormCreate(Sender:TObject);
begin
 IdUDPServer1.DefaultPort:=3030;
 IdUDPServer1.Active:=True;
 Edit1.ReadOnly:=True;
 Edit2.ReadOnly:=True;
 Edit3.ReadOnly:=True;
end;
procedureTServerForm.IdUDPServer1UDPRead(AThread:TIdUDPListenerThread;
 AData:TBytes;ABinding:TIdSocketHandle);
begin
 Edit1.Text:=ABinding.PeerIP;
 Edit2.Text:=IntToStr(ABinding.PeerPort);
 Edit3.Text:=BytesToString(AData);
 IdUDPServer1.Send(ABinding.PeerIP,ABinding.PeerPort,TimeToStr(Time)+'=>Serverreceivedthemessage!');
end;
end.


然后新建客户端如下图所示:

  注意:为了让客户端能实时监控服务端发回来的确定消息,使用了TTimer控件,Interval设置为250毫秒。

Delphi2010的Indy全接触之UDP篇_第2张图片

代码如下:

unitClientUnit;
interface
uses
 Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
 Dialogs,StdCtrls,ExtCtrls,IdBaseComponent,IdComponent,IdUDPBase,
 IdUDPClient;
type
 TClientForm=class(TForm)
  Label1:TLabel;
  Edit1:TEdit;
  Button1:TButton;
  Label2:TLabel;
  Edit2:TEdit;
  IdUDPClient1:TIdUDPClient;
  Timer1:TTimer;
  procedureButton1Click(Sender:TObject);
  procedureFormCreate(Sender:TObject);
  procedureTimer1Timer(Sender:TObject);
 private
  {Privatedeclarations}
 public
  {Publicdeclarations}
 end;
var
 ClientForm:TClientForm;
implementation
{$R*.dfm}
procedureTClientForm.Button1Click(Sender:TObject);
begin
 IdUDPClient1.Broadcast(Edit1.Text,3030);
 Timer1.Enabled:=True;
end;
procedureTClientForm.FormCreate(Sender:TObject);
begin
 Timer1.Enabled:=False;
 Edit2.ReadOnly:=True;
end;
procedureTClientForm.Timer1Timer(Sender:TObject);
begin
 Edit2.Text:=IdUDPClient1.ReceiveString(-1);
 Timer1.Enabled:=False;
end;
end.


如此实现简单的UDP协议下局域网通讯。

  ===================================================

  但是很快我又发现,上面的代码在本机虽然能够正常执行,分别位于2台电脑时会发生无法接收服务器响应的现象。

  究其原因可能是客户程序用户界面“冻结”的缘故。

  于是在服务端和客户端都加上TIdAntiFreeze以解决上面发生的现象(尤其是客户端)。

  服务端:

Delphi2010的Indy全接触之UDP篇_第3张图片

客户端:

Delphi2010的Indy全接触之UDP篇_第4张图片

事实上,上述客户端的TTimer控件是完全没有必要使用的。

  当我们对IdUDPClient使用Broadcast方法后,一旦与服务端通讯成功,IdUDPClient自动会得到来自服务端的返回值。

  如果通讯失败,在IdUDPClient.ReceiveTimeout所设定的事件后终止响应,所以我们可以吧延迟事件稍微设长一点。

  于是客户端代码可以简单的写成:

unitClientUnit;
interface
uses
 Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
 Dialogs,StdCtrls,ExtCtrls,IdBaseComponent,IdComponent,IdUDPBase,
 IdUDPClient,IdAntiFreezeBase,IdAntiFreeze;
type
 TClientForm=class(TForm)
  Label1:TLabel;
  Edit1:TEdit;
  Button1:TButton;
  Label2:TLabel;
  Edit2:TEdit;
  IdUDPClient1:TIdUDPClient;
  IdAntiFreeze1:TIdAntiFreeze;
  procedureButton1Click(Sender:TObject);
  procedureFormCreate(Sender:TObject);
 private
  {Privatedeclarations}
 public
  {Publicdeclarations}
 end;
var
 ClientForm:TClientForm;
implementation
{$R*.dfm}
procedureTClientForm.Button1Click(Sender:TObject);
begin
 IdUDPClient1.Broadcast(Edit1.Text,3030);
 Edit2.Text:=IdUDPClient1.ReceiveString(-1);
end;
procedureTClientForm.FormCreate(Sender:TObject);
begin
 IdUDPClient1.ReceiveTimeout:=5000;
 Edit2.ReadOnly:=True;
end;
end.


如此即可完成与服务端的通讯。

  =======================================================================

  关于网络中查找服务器主机的问题,似乎可以使用UDP广播的方式查找。

  先看代码:

unitClientUnit;
interface
uses
 Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
 Dialogs,StdCtrls,ExtCtrls,IdBaseComponent,IdComponent,IdUDPBase,
 IdUDPClient,IdAntiFreezeBase,IdAntiFreeze;
type
 TClientForm=class(TForm)
  Label1:TLabel;
  Edit1:TEdit;
  Button1:TButton;
  Label2:TLabel;
  IdUDPClient1:TIdUDPClient;
  IdAntiFreeze1:TIdAntiFreeze;
  ListBox1:TListBox;
  Timer1:TTimer;
  procedureButton1Click(Sender:TObject);
  procedureFormCreate(Sender:TObject);
  procedureTimer1Timer(Sender:TObject);
 private
  {Privatedeclarations}
  varIpList:TStringList;
 public
  {Publicdeclarations}
 end;
var
 ClientForm:TClientForm;
implementation
{$R*.dfm}
procedureTClientForm.Button1Click(Sender:TObject);
begin
 IdUDPClient1.Broadcast(Edit1.Text,3030);
 ListBox1.Items.Add(IdUDPClient1.ReceiveString());
end;
procedureTClientForm.FormCreate(Sender:TObject);
begin
 IdUDPClient1.ReceiveTimeout:=10000;
 IpList:=TStringList.Create;
end;
procedureTClientForm.Timer1Timer(Sender:TObject);
varipaddr:string;
varI:Integer;
begin
 IdUDPClient1.BroadcastEnabled:=True;
 IdUDPClient1.Broadcast('SearchHost',3030);
 ipaddr:=IdUDPClient1.ReceiveString();
 ifIpList.IndexOf(ipaddr)=-1then
  IpList.Add(ipaddr);
 ListBox1.Clear;
 forI:=0toIpList.Count-1do
  ListBox1.Items.Add(IpList.Strings[I]);
end;
end.


这样在IpList中就会不断的有主机的IP地址被加入进来了。

  但是实际情况是这样的:

  由于使用了TTimer控件,我这里设置了Interval:5000,如果设置过小会因为线程大量占用而严重影响主程序正常工作,不知道有什么办法来解决这个问题。还有,当网络中没有服务器的任何响应时客户端也会出现假死现象,不知如何解决。

你可能感兴趣的:(windows,工作,网络协议)