上次因為時間的關係,所以把上一個專題遺留下的一個問題在本專題中和大家分享下,本專題主要介紹下如何?UDP廣播的程式,下面就直接介紹實現過程和代碼以及啟動並執行結果。
一、程式實現
UDP廣播程式的實現代碼:
using System;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;using System.Windows.Forms;namespace UDPBroadcast{ /// <summary> /// 在介面上,使用者可以設定本地進程的IP地址和連接埠號碼,並將地址加入某個組播組; /// 可以輸入發送訊息的目的組的地址,並且勾選“廣播”複選框將採用廣播的方式發送資訊 /// 在介面上點擊“接受按鈕”就啟動接收線程,這樣程式就可以接收廣播或組播的資訊 /// </summary> public partial class UdpBroadcasefrm : Form { private UdpClient sendUdpClient; private UdpClient receiveUdpClient; // 組播IP地址 IPEndPoint broadcastIpEndPoint; public UdpBroadcasefrm() { InitializeComponent(); IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName()); tbxlocalip.Text = ips[5].ToString(); tbxlocalport.Text = "8002"; // 預設組,組播地址是有範圍 // 具體關於組播和廣播的介紹參照我上一篇部落格UDP編程 // 本機群組播組 tbxGroupIp.Text = "224.0.0.1"; // 發送到的組播組 tbxSendToGroupIp.Text = "224.0.0.1"; } // 設定加入組 private void chkbxJoinGtoup_Click(object sender, EventArgs e) { if (chkbxJoinGtoup.Checked == true) { tbxGroupIp.Enabled = false; } else { tbxGroupIp.Enabled = true; tbxGroupIp.Focus(); } } // 選擇發送模式後設定 private void chkbxBroadcast_Click(object sender, EventArgs e) { if (chkbxBroadcast.Checked == true) { tbxSendToGroupIp.Enabled = false; } else { tbxSendToGroupIp.Enabled = true; tbxSendToGroupIp.Focus(); } } // 發送訊息 private void btnSend_Click(object sender, EventArgs e) { if (tbxMessageSend.Text == "") { MessageBox.Show("訊息內容不可為空!","提示"); return; } // 根據選擇的模式發送資訊 if (chkbxBroadcast.Checked == true) { // 廣播模式(自動獲得子網中的IP廣播位址) broadcastIpEndPoint = new IPEndPoint(IPAddress.Broadcast, 8002); } else { // 組播模式 broadcastIpEndPoint = new IPEndPoint(IPAddress.Parse(tbxSendToGroupIp.Text), 8002); } // 啟動發送線程發送訊息 Thread sendThread = new Thread(SendMessage); sendThread.Start(tbxMessageSend.Text); } // 發送訊息 private void SendMessage(object obj) { string message = obj.ToString(); byte[] messagebytes = Encoding.Unicode.GetBytes(message); sendUdpClient = new UdpClient(); // 發送訊息到組播或廣播位址 sendUdpClient.Send(messagebytes, messagebytes.Length, broadcastIpEndPoint); sendUdpClient.Close(); // 清空編輯訊息框 ResetMessageText(tbxMessageSend); } // 利用委託回調機制來實現介面上的訊息清空操作 delegate void ResetMessageTextCallBack(TextBox textbox); private void ResetMessageText(TextBox textbox) { if (textbox.InvokeRequired) { ResetMessageTextCallBack resetMessageCallback = ResetMessageText; textbox.Invoke(resetMessageCallback, new object[] { textbox }); } else { textbox.Clear(); textbox.Focus(); } } // 接收訊息 private void btnReceive_Click(object sender, EventArgs e) { chkbxJoinGtoup.Enabled = false; // 建立接收通訊端 IPAddress localIp = IPAddress.Parse(tbxlocalip.Text); IPEndPoint localIpEndPoint = new IPEndPoint(localIp, int.Parse(tbxlocalport.Text)); receiveUdpClient = new UdpClient(localIpEndPoint); // 加入組播組 if (chkbxJoinGtoup.Checked == true) { receiveUdpClient.JoinMulticastGroup(IPAddress.Parse(tbxGroupIp.Text)); receiveUdpClient.Ttl = 50; } // 啟動接受線程 Thread threadReceive = new Thread(ReceiveMessage); threadReceive.Start(); } // 接受訊息方法 private void ReceiveMessage() { IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); while (true) { try { // 關閉receiveUdpClient時此時會產生異常 byte[] receiveBytes = receiveUdpClient.Receive(ref remoteIpEndPoint); string receivemessage = Encoding.Unicode.GetString(receiveBytes); // 顯示訊息內容 ShowMessage(lstMessageBox, string.Format("{0}[{1}]", remoteIpEndPoint, receivemessage)); } catch { break; } } } // 通過委託回調機制顯示訊息內容 delegate void ShowMessageCallBack(ListBox listbox,string text); private void ShowMessage(ListBox listbox, string text) { if (listbox.InvokeRequired) { ShowMessageCallBack showmessageCallback = ShowMessage; listbox.Invoke(showmessageCallback, new object[] { listbox, text }); } else { listbox.Items.Add(text); listbox.SelectedIndex = listbox.Items.Count - 1; listbox.ClearSelected(); } } // 清空訊息列表 private void btnClear_Click(object sender, EventArgs e) { lstMessageBox.Items.Clear(); } // 停止接收 private void btnStop_Click(object sender, EventArgs e) { chkbxJoinGtoup.Enabled =true; receiveUdpClient.Close(); } }}
廣播示範結果(接收端直接點接收按鈕後開啟接受線程,在發送端勾選“廣播選項”輸入發送資訊點發送按鈕後的介面如下):
下面通過把接收端加入組後的結果,首先終止接收線程,然後勾選“加入組”複選框,然後單擊“接收”按鈕重新開啟接收線程,輸出結果如下:
從廣播示範的兩個情況可以看出廣播訊息會同時向網上的一切進程轉寄,無論這個進程是獨立的還是加入了某個組播組中的進程,都可以接收廣播訊息
下面示範下組播的結果:
如果把接收端的組地址改為224.0.0.3時,此時發送端發送的訊息“組播示範2”將不會發送到不同的組播地址,則接收端就接收不到此時的訊息。
從組播結果中可以看出只有加入組播地址224.0.0.2的進程才能接收到資訊。
需要注意的地方是:從前面的中可以看出,不論是廣播還是組播,僅僅從收到的資訊無從知道發送給它的進程的連接埠號碼,所以廣播和組播訊息都是匿名發送,並且通過對UDP廣播和組播的理解可以簡單實現一個訊息群發的功能(QQ的群裡聊天就是這個原理)。
二、 總結
本專題主要是針對上一專題的補充——實現一個簡單的UDP廣播(組播)程式,通過這樣一個發送端可以發送給在組播地址中的所有使用者和所有子網中的所有使用者。本專題可以說是對UDP編程的一個擴充吧,希望大家看了本專題後可以對UDP協議有大致的理解。在下一個專題中會和大家介紹下P2P編程的相關知識。
全部源碼地址:http://files.cnblogs.com/zhili/UDPBroadcast.zip