转自:http://www.cnblogs.com/zhili/archive/2012/09/03/2666974.html

上次因为时间的关系,所以把上一个专题遗留下的一个问题在本专题中和大家分享下,本专题主要介绍下如何实现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

[C# 网络编程系列]专题七:UDP编程补充——UDP广播程序的实现的更多相关文章

  1. [C# 网络编程系列]专题六:UDP编程

    转自:http://www.cnblogs.com/zhili/archive/2012/09/01/2659167.html 引用: 前一个专题简单介绍了TCP编程的一些知识,UDP与TCP地位相当 ...

  2. [C# 网络编程系列]专题九:实现类似QQ的即时通信程序

    转自:http://www.cnblogs.com/zhili/archive/2012/09/23/2666987.html 引言: 前面专题中介绍了UDP.TCP和P2P编程,并且通过一些小的示例 ...

  3. [C# 网络编程系列]专题八:P2P编程

    引言: 前面的介绍专题中有朋友向我留言说介绍下关于P2P相关的内容的,首先本人对于C#网络编程也不是什么大牛,因为能力的关系,也只能把自己的一些学习过程和自己的一些学习过程中的理解和大家分享下的,下面 ...

  4. [C# 网络编程系列]专题四:自定义Web浏览器

    转自:http://www.cnblogs.com/zhili/archive/2012/08/24/WebBrowser.html 前言: 前一个专题介绍了自定义的Web服务器,然而向Web服务器发 ...

  5. [C# 网络编程系列]专题五:TCP编程

    转自:http://www.cnblogs.com/zhili/archive/2012/08/25/2656840.html 前言 前面专题的例子都是基于应用层上的HTTP协议的介绍, 现在本专题来 ...

  6. 详解C# 网络编程系列:实现类似QQ的即时通信程序

    https://www.jb51.net/article/101289.htm 引言: 前面专题中介绍了UDP.TCP和P2P编程,并且通过一些小的示例来让大家更好的理解它们的工作原理以及怎样.Net ...

  7. [C#网络编程系列]专题一:网络协议简介

    转自:http://www.cnblogs.com/zhili/archive/2012/08/11/NetWorkProgramming.html 因为这段时间都在研究C#网络编程的一些知识, 所以 ...

  8. [C# 网络编程系列]专题三:自定义Web服务器

    转自:http://www.cnblogs.com/zhili/archive/2012/08/23/2652460.html 前言: 经过前面的专题中对网络层协议和HTTP协议的简单介绍相信大家对网 ...

  9. [C# 网络编程系列]专题十:实现简单的邮件收发器

    转自:http://www.cnblogs.com/zhili/archive/2012/09/24/2689892.html 引言: 在我们的平常工作中,邮件的发送和接收应该是我们经常要使用到的功能 ...

随机推荐

  1. web services 接口测试方法

    public class Test { public static void main(String[] args) { JaxWsProxyFactoryBean factory = new Jax ...

  2. ORACLE 11g R2数据库安装硬件环境要求

    物理内存要求:最小1G,在windows7,windows8,windows8.1上最小2G. 虚拟内存(或分页空间)容量要求: Available RAM Swap Space Required B ...

  3. objective-c中是如何实现线程同步的?

    多线程在各种编程语言中都是难点,很多语言中实现起来很麻烦,objective-c虽然源于c,但其多线程编程却相当简单,可以与java相媲美.这篇文章主要从线程创建与启动.线程的同步与锁.线程的交互.线 ...

  4. HDU 3442 Three Kingdoms(状态压缩 + BFS )

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3442 题目大意:三国时期,刘备逃亡.给定一个最大为50*50的地图,刘备在地图中只能往4个方向走. 地 ...

  5. ZOJ 1013 Great Equipment(DP)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=13 题目大意:说的是有三种不同的装备,分别是头盔,盔甲,战靴需要运输, ...

  6. (转)Libevent(2)— event、event_base

    转自:http://name5566.com/4198.html 参考文献列表:http://www.wangafu.net/~nickm/libevent-book/ 此文编写的时候,使用到的 Li ...

  7. .net闭包的应用

    这里体现出闭包的数据共享 , , , , , , , , , }; ; ; values.ToList().ForEach(s => result1 += s); values.ToList() ...

  8. git 备份和恢复

    实际应用 设置之前要在个人用户设置中增加key(为了备份ssh的项目) 备份 进入ditlab容器 cd /home/git/gitlab bundle exec rake gitlab:backup ...

  9. web 中 bbs 例子(多次递归)

    数据库设计:create table `header`(  // 父表  parent int not null, //父级  poster varchar(20) not null, //作者  p ...

  10. MVC中Razor视图基本语法(1)

    Razor前面,必须要跟前面的有空隙,即空格(多谢一楼提醒,url里面确实不用空格,如果要在url里面只需要@(ViewBag.),加上括号就好了),之后的必须要连贯,否则加小括号 1,在页面中输出单 ...