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

上次因为时间的关系,所以把上一个专题遗留下的一个问题在本专题中和大家分享下,本专题主要介绍下如何实现UDP广播的程序,下面就直接介绍实现过程和代码以及运行的结果。

一、程序实现

UDP广播程序的实现代码:

[csharp] view plain copy print?

  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Windows.Forms;
  7. namespace UDPBroadcast
  8. {
  9. /// <summary>
  10. /// 在界面上,用户可以设置本地进程的IP地址和端口号,并将地址加入某个组播组;
  11. /// 可以输入发送消息的目的组的地址,并且勾选“广播”复选框将采用广播的方式发送信息
  12. /// 在界面上点击“接受按钮”就启动接收线程,这样程序就可以接收广播或组播的信息
  13. /// </summary>
  14. public partial class UdpBroadcasefrm : Form
  15. {
  16. private UdpClient sendUdpClient;
  17. private UdpClient receiveUdpClient;
  18. // 组播IP地址
  19. IPEndPoint broadcastIpEndPoint;
  20. public UdpBroadcasefrm()
  21. {
  22. InitializeComponent();
  23. IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
  24. tbxlocalip.Text = ips[5].ToString();
  25. tbxlocalport.Text = "8002";
  26. // 默认组,组播地址是有范围
  27. // 具体关于组播和广播的介绍参照我上一篇博客UDP编程
  28. // 本地组播组
  29. tbxGroupIp.Text = "224.0.0.1";
  30. // 发送到的组播组
  31. tbxSendToGroupIp.Text = "224.0.0.1";
  32. }
  33. // 设置加入组
  34. private void chkbxJoinGtoup_Click(object sender, EventArgs e)
  35. {
  36. if (chkbxJoinGtoup.Checked == true)
  37. {
  38. tbxGroupIp.Enabled = false;
  39. }
  40. else
  41. {
  42. tbxGroupIp.Enabled = true;
  43. tbxGroupIp.Focus();
  44. }
  45. }
  46. // 选择发送模式后设置
  47. private void chkbxBroadcast_Click(object sender, EventArgs e)
  48. {
  49. if (chkbxBroadcast.Checked == true)
  50. {
  51. tbxSendToGroupIp.Enabled = false;
  52. }
  53. else
  54. {
  55. tbxSendToGroupIp.Enabled = true;
  56. tbxSendToGroupIp.Focus();
  57. }
  58. }
  59. // 发送消息
  60. private void btnSend_Click(object sender, EventArgs e)
  61. {
  62. if (tbxMessageSend.Text == "")
  63. {
  64. MessageBox.Show("消息内容不能为空!","提示");
  65. return;
  66. }
  67. // 根据选择的模式发送信息
  68. if (chkbxBroadcast.Checked == true)
  69. {
  70. // 广播模式(自动获得子网中的IP广播地址)
  71. broadcastIpEndPoint = new IPEndPoint(IPAddress.Broadcast, 8002);
  72. }
  73. else
  74. {
  75. // 组播模式
  76. broadcastIpEndPoint = new IPEndPoint(IPAddress.Parse(tbxSendToGroupIp.Text), 8002);
  77. }
  78. // 启动发送线程发送消息
  79. Thread sendThread = new Thread(SendMessage);
  80. sendThread.Start(tbxMessageSend.Text);
  81. }
  82. // 发送消息
  83. private void SendMessage(object obj)
  84. {
  85. string message = obj.ToString();
  86. byte[] messagebytes = Encoding.Unicode.GetBytes(message);
  87. sendUdpClient = new UdpClient();
  88. // 发送消息到组播或广播地址
  89. sendUdpClient.Send(messagebytes, messagebytes.Length, broadcastIpEndPoint);
  90. sendUdpClient.Close();
  91. // 清空编辑消息框
  92. ResetMessageText(tbxMessageSend);
  93. }
  94. // 利用委托回调机制来实现界面上的消息清空操作
  95. delegate void ResetMessageTextCallBack(TextBox textbox);
  96. private void ResetMessageText(TextBox textbox)
  97. {
  98. if (textbox.InvokeRequired)
  99. {
  100. ResetMessageTextCallBack resetMessageCallback = ResetMessageText;
  101. textbox.Invoke(resetMessageCallback, new object[] { textbox });
  102. }
  103. else
  104. {
  105. textbox.Clear();
  106. textbox.Focus();
  107. }
  108. }
  109. // 接收消息
  110. private void btnReceive_Click(object sender, EventArgs e)
  111. {
  112. chkbxJoinGtoup.Enabled = false;
  113. // 创建接收套接字
  114. IPAddress localIp = IPAddress.Parse(tbxlocalip.Text);
  115. IPEndPoint localIpEndPoint = new IPEndPoint(localIp, int.Parse(tbxlocalport.Text));
  116. receiveUdpClient = new UdpClient(localIpEndPoint);
  117. // 加入组播组
  118. if (chkbxJoinGtoup.Checked == true)
  119. {
  120. receiveUdpClient.JoinMulticastGroup(IPAddress.Parse(tbxGroupIp.Text));
  121. receiveUdpClient.Ttl = 50;
  122. }
  123. // 启动接受线程
  124. Thread threadReceive = new Thread(ReceiveMessage);
  125. threadReceive.Start();
  126. }
  127. // 接受消息方法
  128. private void ReceiveMessage()
  129. {
  130. IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
  131. while (true)
  132. {
  133. try
  134. {
  135. // 关闭receiveUdpClient时此时会产生异常
  136. byte[] receiveBytes = receiveUdpClient.Receive(ref remoteIpEndPoint);
  137. string receivemessage = Encoding.Unicode.GetString(receiveBytes);
  138. // 显示消息内容
  139. ShowMessage(lstMessageBox, string.Format("{0}[{1}]", remoteIpEndPoint, receivemessage));
  140. }
  141. catch
  142. {
  143. break;
  144. }
  145. }
  146. }
  147. // 通过委托回调机制显示消息内容
  148. delegate void ShowMessageCallBack(ListBox listbox,string text);
  149. private void ShowMessage(ListBox listbox, string text)
  150. {
  151. if (listbox.InvokeRequired)
  152. {
  153. ShowMessageCallBack showmessageCallback = ShowMessage;
  154. listbox.Invoke(showmessageCallback, new object[] { listbox, text });
  155. }
  156. else
  157. {
  158. listbox.Items.Add(text);
  159. listbox.SelectedIndex = listbox.Items.Count - 1;
  160. listbox.ClearSelected();
  161. }
  162. }
  163. // 清空消息列表
  164. private void btnClear_Click(object sender, EventArgs e)
  165. {
  166. lstMessageBox.Items.Clear();
  167. }
  168. // 停止接收
  169. private void btnStop_Click(object sender, EventArgs e)
  170. {
  171. chkbxJoinGtoup.Enabled =true;
  172. receiveUdpClient.Close();
  173. }
  174. }
  175. }

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

时间: 2024-08-09 06:35:31

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

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

转自:http://www.cnblogs.com/zhili/archive/2012/09/01/2659167.html 引用: 前一个专题简单介绍了TCP编程的一些知识,UDP与TCP地位相当的另一个传输层协议,它也是当下流行的很多主流网络应用(例如QQ.MSN和Skype等一些即时通信软件传输层都是应用UDP协议的)底层的传输基础,所以在本专题中就简单介绍下UDP的工作原理和UDP编程的只是,希望可以对刚接触网络编程的朋友起到入门的作用. 一.UDP介绍 UDP和TCP都是构建在IP层

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

转自:http://www.cnblogs.com/zhili/archive/2012/09/23/2666987.html 引言: 前面专题中介绍了UDP.TCP和P2P编程,并且通过一些小的示例来让大家更好的理解它们的工作原理以及怎样.Net类库去实现它们的.为了让大家更好的理解我们平常中常见的软件QQ的工作原理,所以在本专题中将利用前面专题介绍的知识来实现一个类似QQ的聊天程序. 一.即时通信系统 在我们的生活中经常使用即时通信的软件,我们经常接触到的有:QQ.阿里旺旺.MSN等等.这些

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

转自:http://www.cnblogs.com/zhili/archive/2012/08/24/WebBrowser.html 前言: 前一个专题介绍了自定义的Web服务器,然而向Web服务器发出请求的正是本专题要介绍的Web浏览器,本专题通过简单自定义一个Web浏览器来简单介绍浏览器的工作原理,以及帮助一些初学者揭开浏览器这层神秘的面纱(以前总感觉这些应用感觉很深奥的,没想到自己也可以自定义一个浏览器出来),下面不啰嗦了,进入正题. 一.Web浏览器的介绍 Web浏览器是指可以显示Web

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

转自:http://www.cnblogs.com/zhili/archive/2012/08/23/2652460.html 前言: 经过前面的专题中对网络层协议和HTTP协议的简单介绍相信大家对网络中的协议有了大致的了解的, 本专题将针对HTTP协议定义一个Web服务器,我们平常浏览网页通过在浏览器中输入一个网址就可以看到我们想要的网页,这个过程中浏览器只是一个客户端,浏览器(应用层应用程序)通过HTTP协议把用户请求发送到服务端, 服务器接受到发送来的HTTP请求,然后对请求进行处理和响应

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

转自:http://www.cnblogs.com/zhili/archive/2012/09/24/2689892.html 引言: 在我们的平常工作中,邮件的发送和接收应该是我们经常要使用到的功能的.因此知道电子邮件的应用程序的原理也是非常有必要的,在这一个专题中将介绍电子邮件应用程序的原理.电子邮件应用程序中涉及的协议和实现一个简答的电子邮件收发器程序. 一.邮件应用程序基本知识 1.1 电子邮件原理及相关协议 说到电子邮件的原理,其实和我们现实生活中寄邮件和寄包裹是一样的原理的.就让我们

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

引言: 前面专题中介绍了UDP.TCP和P2P编程,并且通过一些小的示例来让大家更好的理解它们的工作原理以及怎样.Net类库去实现它们的.为了让大家更好的理解我们平常中常见的软件QQ的工作原理,所以在本专题中将利用前面专题介绍的知识来实现一个类似QQ的聊天程序.  一.即时通信系统 在我们的生活中经常使用即时通信的软件,我们经常接触到的有:QQ.阿里旺旺.MSN等等.这些都是属于即时通信(Instant Messenger,IM)软件,IM是指所有能够即时发送和接收互联网消息的软件. 在前面专题

C#网络编程系列文章(七)之UdpClient实现异步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 本文介绍 UdpClient 类在同步阻塞模式中为发送和接收无连接的 UDP 数据包而提供了简单的方法.因为 UDP 是一种无连接的传输协议,所以你不需要在发送和接收数据之前建立任何远程主机连接.你只需要按照下列方式来建立默认的远程主机选项: 使用远程主机名称和端口号作为参数来创建 UdpClient 类的实例. 创建 Udp

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

原文地址:http://blog.csdn.net/learning_hard/article/details/9004936 一.网络分层 网络上的计算机之所以可以互相通信,是因为它们之间都遵守互相都可以"认识"的互联网协议(就如同人交流一样,两个人能够交流,互相必须知道对象的语言),互联网上的计算机互相通信又归根于网络中层与层之间的通信,OSI模型把网络通信分成七层:物理层.数据链路层.网络层.传输层.会话层.表示层和应用层,对于开发网络应用人员来说,一般把网络分成五层,这样比较容

[C#]网络编程系列专题二:HTTP协议详解

一.HTTP协议的简介 HTTP中文为超文本传输协议,从名字上很容易理解,Http协议就是将超文本标记语言的文档(即Html文档)从web服务传送到客户端的浏览器.它属于一个应用层的协议. 二.网络的工作过程 当用户要访问网络中的某个网页时,大致要经过以下几个步骤: 用户首先要确定网页文件所在的URL(统一资源定位符,也就是网页在网络上的家庭住址,通过这个地址就可以找到这个网页)如www.cnblogs.com 浏览器向DNS(域名服务器)发出请求,告诉DNS说:"我要把www.cnblogs.