在System.net.Sockets名称空间中,UdpClient类简化了UDP套接字编程。UDP协议是无连接的协议,因此,UDP协议只有UdpClient类,而没有TcpListener类和TcpClient类。UdpClient类提供了发送和接受无连接的UDP数据报的方便方法。其建立默认远程主机的方式有两种:一是使用远程主机名和端口号作为参数创建UdpClient类的实例;另一种是先创建不带参数的UdpClient类的实例,然后调用Connet方法指定默认远程主机。
可以通过调用UdpClient对象的Send方法直接将数据发送到远程主机,该方法返回数据的长度可用于检查数据是否已被正确发送。UdpClient对象的Receive方法能够在指定的本地IP地址和端口上接收数据,该方法带一个引用类型的IPEndPoint实例,并将接收到的数据作为byte数组返回
UDP协议的重要用途是可以通过广播和组播实现一对多的通信。所谓广播,就是指同时向网络中的所有计算机发送消息,而这些计算机都可以接收到消息。组播也叫多路广播,是将消息从一台计算机发送到网络中指定的若干台计算机上,即发送到哪些加入指定组播组的计算机上,组播组是开放的,每台计算机都可以通过程序随时加入到组播组中,也可以随时退出。
组播地址是224.0.0.0到239.255.255.255的D类IP地址。使用组播时,应注意的是TTL值的设置,TTL值是允许路由器转发的最大数目。当达到这个最大值时,数据包就会被丢弃。如果使用默认值(1),则只能在同一子网内部发送。
在UdpClient类中,调用JoinMulticastGroup方法可将UdpClient对象和TTL一起加入组播组,调用DropMulticastGroup方法可退出组播组。
编写一个程序,利用组播技术向子网发送组播信息,同时接收组播的信息。
按顺序启动组播发送方与组播接收方程序,在组播发送方输入信息并单击“发送”按钮。该消息经UDP协议广播并成功的被组播接收方接收
运行结果:
源代码:
发送端:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Socket_UdpSender
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//系统将自动分配最合适的本地地址和端口号
UdpClient client = new UdpClient();
//允许发送广播
client.EnableBroadcast = true;
//必须使用组播地址
IPEndPoint p = new IPEndPoint(IPAddress.Parse("224.0.0.2"), 8001);
//将发送内容装换为字节数组
byte[] bytes = Encoding.UTF8.GetBytes(textSend.Text);
try
{
//向子网发送信息
client.Send(bytes, bytes.Length, p);
textSend.Clear();
textSend.Focus();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "发送错误");
}
finally
{
client.Close();
}
}
}
}
接收端:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Socket_UdpReceiver
{
public partial class Form1 : Form
{
private delegate void AppendStringCallBack(string text); //定义委托
private AppendStringCallBack OnAppendStringCallback; //定义回调事件
private UdpClient client; //定义udp客户端对象
public Form1() //窗体类的构造函数
{
InitializeComponent();
OnAppendStringCallback = new AppendStringCallBack(AppendString); //绑定事件
}
private void AppendString(string text) //定义事件方法
{
//Windows窗体中的控件被绑定到特定的线程,不具备线程安全性
//因此,若从另一个线程调用控件的方法,则必须使用Invoke方法来调用封送到适当的线程
//InvokeRequired属性用于确定是否必须调用Invoke方法
if (textReceive.InvokeRequired)
this.Invoke(OnAppendStringCallback, text);
else
textReceive.AppendText(text + "\r\n"); //触发事件,执行在另一个线程中订阅事件方法
}
//该方法先加入主播接收主播消息,再订阅事件方法AppendSting。当onAppendStringcallBack事件被触发时将
//收到的信息添加到RichTextBox控件,以便显示消息。为了自动接收消息,ReceiveData方法不能在运行Windows
//窗体线程中运行,须把ReceiveData创建为一个新的线程。为此,在窗体的Load事件中创建新线程。
private void ReceiveData()
{
//在本机指定的端口接收
client = new UdpClient(8001);
IPEndPoint remove = null;
//不知道为啥用224.0.0.1就会出现套接字无法连接主机的错误,也许是防火墙的问题?
//加入组播,注意必须使用组播地址范围内的地址
client.JoinMulticastGroup(IPAddress.Parse("224.0.0.2"));
client.Ttl = 50;
while (true) //接收从远程主机发送过来的信息
{
try
{
byte[] bytes = client.Receive(ref remove);
string data = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
//订阅事件
AppendString(string.Format("来自{0}:{1}", remove, data));
}
catch
{
break; //退出循环,结束线程
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
Thread showThread = new Thread(new ThreadStart(ReceiveData));
showThread.Start();
}
//在关闭窗体时先关闭UdpClient
private void Form1_FormClosing_1(object sender, FormClosingEventArgs e)
{
client.Close();
}
}
}