首先新建服務端。
如下圖所示建立工程:
代碼如下:
1.unit ServerUnit;
2.
3.interface
4.
5.uses
6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7. Dialogs, IdBaseComponent, IdComponent, IdUDPBase, IdUDPServer, StdCtrls,
8. IdSocketHandle, IdGlobal;
9.
10.type
11. TServerForm = class(TForm)
12. Label1: TLabel;
13. Edit1: TEdit;
14. Label2: TLabel;
15. Edit2: TEdit;
16. Label3: TLabel;
17. Edit3: TEdit;
18. IdUDPServer1: TIdUDPServer;
19. procedure IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; AData: TBytes;
20. ABinding: TIdSocketHandle);
21. procedure FormCreate(Sender: TObject);
22. private
23. { Private declarations }
24. public
25. { Public declarations }
26. end;
27.
28.var
29. ServerForm: TServerForm;
30.
31.implementation
32.
33.{$R *.dfm}
34.
35.procedure TServerForm.FormCreate(Sender: TObject);
36.begin
37. IdUDPServer1.DefaultPort := 3030;
38. IdUDPServer1.Active := True;
39.
40. Edit1.ReadOnly := True;
41. Edit2.ReadOnly := True;
42. Edit3.ReadOnly := True;
43.end;
44.
45.procedure TServerForm.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
46. AData: TBytes; ABinding: TIdSocketHandle);
47.begin
48. Edit1.Text := ABinding.PeerIP;
49. Edit2.Text := IntToStr(ABinding.PeerPort);
50. Edit3.Text := BytesToString(AData);
51.
52. IdUDPServer1.Send(ABinding.PeerIP, ABinding.PeerPort, TimeToStr(Time) + ' => Server received the message!');
53.end;
54.
55.end.
然後新建客戶端如下圖所示:
注意:為了讓客戶端能實時監控服務端發回來的確定消息,使用了TTimer控件,Interval設置為250毫秒。
代碼如下:
1.unit ClientUnit;
2.
3.interface
4.
5.uses
6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7. Dialogs, StdCtrls, ExtCtrls, IdBaseComponent, IdComponent, IdUDPBase,
8. IdUDPClient;
9.
10.type
11. TClientForm = class(TForm)
12. Label1: TLabel;
13. Edit1: TEdit;
14. Button1: TButton;
15. Label2: TLabel;
16. Edit2: TEdit;
17. IdUDPClient1: TIdUDPClient;
18. Timer1: TTimer;
19. procedure Button1Click(Sender: TObject);
20. procedure FormCreate(Sender: TObject);
21. procedure Timer1Timer(Sender: TObject);
22. private
23. { Private declarations }
24. public
25. { Public declarations }
26. end;
27.
28.var
29. ClientForm: TClientForm;
30.
31.implementation
32.
33.{$R *.dfm}
34.
35.procedure TClientForm.Button1Click(Sender: TObject);
36.begin
37. IdUDPClient1.Broadcast(Edit1.Text, 3030);
38. Timer1.Enabled := True;
39.end;
40.
41.procedure TClientForm.FormCreate(Sender: TObject);
42.begin
43. Timer1.Enabled := False;
44.
45. Edit2.ReadOnly := True;
46.end;
47.
48.procedure TClientForm.Timer1Timer(Sender: TObject);
49.begin
50. Edit2.Text := IdUDPClient1.ReceiveString(-1);
51. Timer1.Enabled := False;
52.end;
53.
54.end.
如此實現簡單的UDP協議下局域網通訊。
===================================================
但是很快我又發現,上面的代碼在本機雖然能夠正常執行,分別位於2台電腦時會發生無法接收服務器響應的現象。
究其原因可能是客戶程序用戶界面“凍結”的緣故。
於是在服務端和客戶端都加上TIdAntiFreeze以解決上面發生的現象(尤其是客戶端)。
服務端:
客戶端:
事實上,上述客戶端的TTimer控件是完全沒有必要使用的。
當我們對IdUDPClient使用Broadcast方法後,一旦與服務端通訊成功,IdUDPClient自動會得到來自服務端的返回值。
如果通訊失敗,在IdUDPClient.ReceiveTimeout所設定的事件後終止響應,所以我們可以吧延遲事件稍微設長一點。
於是客戶端代碼可以簡單的寫成:
1.unit ClientUnit;
2.
3.interface
4.
5.uses
6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7. Dialogs, StdCtrls, ExtCtrls, IdBaseComponent, IdComponent, IdUDPBase,
8. IdUDPClient, IdAntiFreezeBase, IdAntiFreeze;
9.
10.type11. TClientForm = class(TForm)
12. Label1: TLabel;
13. Edit1: TEdit;
14. Button1: TButton;
15. Label2: TLabel;
16. Edit2: TEdit;
17. IdUDPClient1: TIdUDPClient;
18. IdAntiFreeze1: TIdAntiFreeze;
19. procedure Button1Click(Sender: TObject);
20. procedure FormCreate(Sender: TObject);
21. private
22. { Private declarations }
23. public
24. { Public declarations }
25. end;
26.
27.var
28. ClientForm: TClientForm;
29.
30.implementation
31.
32.{$R *.dfm}
33.
34.procedure TClientForm.Button1Click(Sender: TObject);
35.begin
36. IdUDPClient1.Broadcast(Edit1.Text, 3030);
37. Edit2.Text := IdUDPClient1.ReceiveString(-1);
38.end;
39.
40.procedure TClientForm.FormCreate(Sender: TObject);
41.begin
42. IdUDPClient1.ReceiveTimeout := 5000;
43. Edit2.ReadOnly := True;
44.end;
45.
46.end.
如此即可完成與服務端的通訊。
=======================================================================
關於網絡中查找服務器主機的問題,似乎可以使用UDP廣播的方式查找。
先看代碼:
1.unit ClientUnit;
2.
3.interface
4.
5.uses
6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7. Dialogs, StdCtrls, ExtCtrls, IdBaseComponent, IdComponent, IdUDPBase,
8. IdUDPClient, IdAntiFreezeBase, IdAntiFreeze;
9.
10.type
11. TClientForm = class(TForm)
12. Label1: TLabel;
13. Edit1: TEdit;
14. Button1: TButton;
15. Label2: TLabel;
16. IdUDPClient1: TIdUDPClient;
17. IdAntiFreeze1: TIdAntiFreeze;
18. ListBox1: TListBox;
19. Timer1: TTimer;
20. procedure Button1Click(Sender: TObject);
21. procedure FormCreate(Sender: TObject);
22. procedure Timer1Timer(Sender: TObject);
23. private
24. { Private declarations }
25. var IpList : TStringList;
26. public
27. { Public declarations }
28. end;
29.
30.var
31. ClientForm: TClientForm;
32.
33.implementation
34.
35.{$R *.dfm}
36.
37.procedure TClientForm.Button1Click(Sender: TObject);
38.begin
39. IdUDPClient1.Broadcast(Edit1.Text, 3030);
40. ListBox1.Items.Add(IdUDPClient1.ReceiveString());
41.end;
42.
43.procedure TClientForm.FormCreate(Sender: TObject);
44.begin
45. IdUDPClient1.ReceiveTimeout := 10000;
46.
47. IpList := TStringList.Create;
48.end;
49.
50.procedure TClientForm.Timer1Timer(Sender: TObject);
51.var ipaddr : string;
52.var I : Integer;
53.begin
54. IdUDPClient1.BroadcastEnabled := True;
55. IdUDPClient1.Broadcast('SearchHost', 3030);
56. ipaddr := IdUDPClient1.ReceiveString();
57. if IpList.IndexOf(ipaddr) = -1 then
58. IpList.Add(ipaddr);
59.
60. ListBox1.Clear;
61. for I := 0 to IpList.Count - 1 do
62. ListBox1.Items.Add(IpList.Strings[I]);
63.end;
64.
65.end.
這樣在IpList中就會不斷的有主機的IP地址被加入進來了。
但是實際情況是這樣的:
由於使用了TTimer控件,我這裡設置了Interval:5000,如果設置過小會因為線程大量占用而嚴重影響主程序正常工作,不知道有什麼辦法來解決這個問題。還有,當網絡中沒有服務器的任何響應時客戶端也會出現假死現象,不知如何解決。