上次因为时间的关系,所以把上一个专题遗留下的一个问题在本专题中和大家分享下,本专题主要介绍下如何实现UDP广播的程序,下面就直接介绍实现过程和代码以及运行的结果。
一、程序实现
UDP广播程序的实现代码:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace MyUDPBroadcast
{
/// <summary>
/// 在界面上,用户可以设置本地进程的IP地址和端口号,并将地址加入某个组播组;
/// 可以输入发送消息的目的组的地址,并且勾选“广播”复选框将采用广播的方式发送信息
/// 在界面上点击“接受按钮”就启动接收线程,这样程序就可以接收广播或组播的信息
/// </summary>
public partial class UDPBroadcast : Form
{
private UdpClient _sendUdpClient;
private UdpClient _acceptUdpClient;
//组播IP地址
private IPEndPoint _broadcastIpEndPoint;
public UDPBroadcast()
{
InitializeComponent();
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
txtLocalIP.Text = ips[2].ToString();
txtLocalPort.Text = "8002";
//默认组,组播地址是有范围
//具体关于组播和广播的介绍参照我上一篇博客UDP编程
//本地组播组
txtLocalGroup.Text = "224.0.0.1";
//发送到的组播组
txtSendToGroup.Text = "224.0.0.1";
}
/// <summary>
/// 加入组
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void chkAddGroup_CheckedChanged(object sender, EventArgs e)
{
txtLocalGroup.Enabled = !chkAddGroup.Checked;
}
//选择发送模式后设置
private void chkSendToBroadcast_CheckedChanged(object sender, EventArgs e)
{
txtSendToGroup.Enabled = !chkSendToBroadcast.Checked;
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
if (txtMessage.Text == "")
{
MessageBox.Show("消息内容不能为空!", "提示");
return;
}
//根据选择模式发送信息
if (chkSendToBroadcast.Checked)
{
//广播模式(自动获得子网中的IP广播地址)
_broadcastIpEndPoint = new IPEndPoint(IPAddress.Broadcast, 8002);
}
else
{
//组播模式
_broadcastIpEndPoint = new IPEndPoint(IPAddress.Parse(txtSendToGroup.Text), 8002);
}
//启动发送线程发送消息
Thread sendThread = new Thread(SendMessage);
sendThread.Start(txtMessage.Text);
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="obj">消息</param>
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();
//清空编辑消息框
ClearnMessageText(txtMessage);
}
//利用委托回调机制来实现界面上的消息清空操作
delegate void ClearnMessageTextCallBack(TextBox textBox);
/// <summary>
/// 清空消息文本框
/// </summary>
/// <param name="textBox">TextBox</param>
private void ClearnMessageText(TextBox textBox)
{
if (textBox.InvokeRequired)
{
ClearnMessageTextCallBack clearnMessageCallback = ClearnMessageText;
textBox.Invoke(clearnMessageCallback, textBox);
}
else
{
txtMessage.Clear();
txtMessage.Focus();
}
}
/// <summary>
/// 接收消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnAccept_Click(object sender, EventArgs e)
{
chkAddGroup.Enabled = false;
//创建接收套接字
IPAddress localIp = IPAddress.Parse(txtLocalIP.Text);
IPEndPoint localIpEndPoint = new IPEndPoint(localIp, int.Parse(txtLocalPort.Text));
_acceptUdpClient = new UdpClient(localIpEndPoint);
//加入组播组
if (chkAddGroup.Checked)
{
_acceptUdpClient.JoinMulticastGroup(IPAddress.Parse(txtSendToGroup.Text));
_acceptUdpClient.Ttl = 50;
}
//启动接收线程
Thread acceptThread = new Thread(AcceptMessage);
acceptThread.Start();
}
/// <summary>
/// 接收消息
/// </summary>
private void AcceptMessage()
{
IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
try
{
//关闭_acceptUdpClient时此时会产生异常
byte[] acceptBytes = _acceptUdpClient.Receive(ref remoteIpEndPoint);
string acceptMessage = Encoding.Unicode.GetString(acceptBytes);
//显示消息内容
ShowMessage(lstMessage, string.Format("{0}:[{1}]", remoteIpEndPoint, acceptMessage));
}
catch
{
break;
}
}
}
//通过回调机制显示消息
delegate void ShowMessageCallBack(ListBox lstbox, string text);
/// <summary>
/// 显示消息内容
/// </summary>
/// <param name="lstBox">ListBox</param>
/// <param name="text">消息内容</param>
private void ShowMessage(ListBox lstBox, string text)
{
if (lstBox.InvokeRequired)
{
ShowMessageCallBack showMessageCallback = ShowMessage;
lstBox.Invoke(showMessageCallback, lstBox, text);
}
else
{
lstMessage.Items.Add(text);
lstMessage.SelectedIndex = lstMessage.Items.Count - 1;
lstMessage.ClearSelected();
}
}
/// <summary>
/// 清空消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClearn_Click(object sender, EventArgs e)
{
lstMessage.Items.Clear();
}
/// <summary>
/// 停止接收
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStop_Click(object sender, EventArgs e)
{
chkAddGroup.Enabled = true;
_acceptUdpClient.Close();
}
}
}
效果图如下:
从广播演示的两个情况可以看出广播消息会同时向网上的一切进程转发,无论这个进程是独立的还是加入了某个组播组中的进程,都可以接收广播消息。
从组播结果中可以看出只有加入组播地址的进程才能接收到信息。
需要注意的地方是:从前面的截图中可以看出,不论是广播还是组播,仅仅从收到的信息无从知道发送给它的进程的端口号,所以广播和组播消息都是匿名发送,并且通过对UDP广播和组播的理解可以简单实现一个消息群发的功能(QQ的群里聊天就是这个原理)。
二、 总结
本专题主要是针对上一专题的补充——实现一个简单的UDP广播(组播)程序,通过这样一个发送端可以发送给在组播地址中的所有用户和所有子网中的所有用户。本专题可以说是对UDP编程的一个扩充吧,希望大家看了本专题后可以对UDP协议有大致的理解。在下一个专题中会和大家介绍下P2P编程的相关知识。
本文源码:点击打开链接原文地址:点击打开链接