首先新建服务端。
如下图所示建立工程:
代码如下:
- unit ServerUnit;
- 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;
- procedure IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; AData: TBytes;
- ABinding: TIdSocketHandle);
- procedure FormCreate(Sender: TObject);
- private
- { Private declarations }
- public
- { Public declarations }
- end;
- var
- ServerForm: TServerForm;
- implementation
- {$R *.dfm}
- procedure TServerForm.FormCreate(Sender: TObject);
- begin
- IdUDPServer1.DefaultPort := 3030;
- IdUDPServer1.Active := True;
- Edit1.ReadOnly := True;
- Edit2.ReadOnly := True;
- Edit3.ReadOnly := True;
- end;
- procedure TServerForm.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) + ' => Server received the message!');
- end;
- end.
然后新建客户端如下图所示:
注意:为了让客户端能实时监控服务端发回来的确定消息,使用了TTimer控件,Interval设置为250毫秒。
代码如下:
- unit ClientUnit;
- 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;
- procedure Button1Click(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure Timer1Timer(Sender: TObject);
- private
- { Private declarations }
- public
- { Public declarations }
- end;
- var
- ClientForm: TClientForm;
- implementation
- {$R *.dfm}
- procedure TClientForm.Button1Click(Sender: TObject);
- begin
- IdUDPClient1.Broadcast(Edit1.Text, 3030);
- Timer1.Enabled := True;
- end;
- procedure TClientForm.FormCreate(Sender: TObject);
- begin
- Timer1.Enabled := False;
- Edit2.ReadOnly := True;
- end;
- procedure TClientForm.Timer1Timer(Sender: TObject);
- begin
- Edit2.Text := IdUDPClient1.ReceiveString(-1);
- Timer1.Enabled := False;
- end;
- end.
如此实现简单的UDP协议下局域网通讯。
===================================================
但是很快我又发现,上面的代码在本机虽然能够正常执行,分别位于2台电脑时会发生无法接收服务器响应的现象。
究其原因可能是客户程序用户界面“冻结”的缘故。
于是在服务端和客户端都加上TIdAntiFreeze以解决上面发生的现象(尤其是客户端)。
服务端:
客户端:
事实上,上述客户端的TTimer控件是完全没有必要使用的。
当我们对IdUDPClient使用Broadcast方法后,一旦与服务端通讯成功,IdUDPClient自动会得到来自服务端的返回值。
如果通讯失败,在IdUDPClient.ReceiveTimeout所设定的事件后终止响应,所以我们可以吧延迟事件稍微设长一点。
于是客户端代码可以简单的写成:
- unit ClientUnit;
- 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;
- procedure Button1Click(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- private
- { Private declarations }
- public
- { Public declarations }
- end;
- var
- ClientForm: TClientForm;
- implementation
- {$R *.dfm}
- procedure TClientForm.Button1Click(Sender: TObject);
- begin
- IdUDPClient1.Broadcast(Edit1.Text, 3030);
- Edit2.Text := IdUDPClient1.ReceiveString(-1);
- end;
- procedure TClientForm.FormCreate(Sender: TObject);
- begin
- IdUDPClient1.ReceiveTimeout := 5000;
- Edit2.ReadOnly := True;
- end;
- end.
如此即可完成与服务端的通讯。
=======================================================================
关于网络中查找服务器主机的问题,似乎可以使用UDP广播的方式查找。
先看代码:
- unit ClientUnit;
- 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;
- procedure Button1Click(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure Timer1Timer(Sender: TObject);
- private
- { Private declarations }
- var IpList : TStringList;
- public
- { Public declarations }
- end;
- var
- ClientForm: TClientForm;
- implementation
- {$R *.dfm}
- procedure TClientForm.Button1Click(Sender: TObject);
- begin
- IdUDPClient1.Broadcast(Edit1.Text, 3030);
- ListBox1.Items.Add(IdUDPClient1.ReceiveString());
- end;
- procedure TClientForm.FormCreate(Sender: TObject);
- begin
- IdUDPClient1.ReceiveTimeout := 10000;
- IpList := TStringList.Create;
- end;
- procedure TClientForm.Timer1Timer(Sender: TObject);
- var ipaddr : string;
- var I : Integer;
- begin
- IdUDPClient1.BroadcastEnabled := True;
- IdUDPClient1.Broadcast('SearchHost', 3030);
- ipaddr := IdUDPClient1.ReceiveString();
- if IpList.IndexOf(ipaddr) = -1 then
- IpList.Add(ipaddr);
- ListBox1.Clear;
- for I := 0 to IpList.Count - 1 do
- ListBox1.Items.Add(IpList.Strings[I]);
- end;
- end.
这样在IpList中就会不断的有主机的IP地址被加入进来了。
但是实际情况是这样的:
由于使用了TTimer控件,我这里设置了Interval:5000,如果设置过小会因为线程大量占用而严重影响主程序正常工作,不知道有什么办法来解决这个问题。还有,当网络中没有服务器的任何响应时客户端也会出现假死现象,不知如何解决。