UDP协议详解——使用Socket通信
UDP(UserDatagramProtocol)是一个简单的面向消息的传输层协议,尽管UDP提供标头和有效负载的完整性验证(通过校验和),但它不保证向上层协议提供消息传递,并且UDP层在发送后不会保留UDP 消息的状态。因此,UDP有时被称为不可靠的数据报协议。如果需要传输可靠性,则必须在用户应用程序中实现。UDP使用具有最小协议机制的简单无连接通信模型。UDP提供数据完整性的校验和,以及用于在
目录
UDP协议
UDP(UserDatagramProtocol)是一个简单的面向消息的传输层协议,尽管UDP提供标头和有效负载的完整性验证(通过校验和),但它不保证向上层协议提供消息传递,并且UDP层在发送后不会保留UDP 消息的状态。因此,UDP有时被称为不可靠的数据报协议。如果需要传输可靠性,则必须在用户应用程序中实现。
UDP使用具有最小协议机制的简单无连接通信模型。UDP提供数据完整性的校验和,以及用于在数据报的源和目标寻址不同函数的端口号。它没有握手对话,因此将用户的程序暴露在底层网络的任何不可靠的方面。如果在网络接口级别需要纠错功能,应用程序可以使用为此目的设计的传输控制协议(TCP)。
综上所述:
* UDP是基于IP的简单协议,不可靠的协议。
* UDP的优点:简单,轻量化。
* UDP的缺点:没有流控制,没有应答确认机制,不能解决丢包、重发、错序问题。
这里需要注意一点,并不是所有使用UDP协议的应用层都是不可靠的,应用程序可以自己实现可靠的数据传输,通过增加确认和重传机制,所以使用UDP 协议最大的特点就是速度快。
优点:
低延迟:UDP通信不需要像TCP那样进行连接的建立和维护,因此具有较低的延迟,适合对实时性要求高的应用场景。
简单轻量:UDP协议相比于TCP协议更加简单,不需要进行连接管理、流量控制等,因此实现起来更加轻量级。
适用于大规模数据传输:UDP支持多播和广播,可以方便地向多个主机发送数据,适用于大规模数据传输的场景。
缺点:
不可靠性:UDP通信不提供数据传输的可靠性机制,数据包可能丢失或乱序,需要应用层自行处理。
无拥塞控制:UDP协议没有拥塞控制机制,当网络拥塞时可能会导致数据丢失或延迟增加。
不适用于大文件传输:由于UDP通信不提供流量控制和分段重组机制,不适合大文件的传输。
UDP应用场景
当应用程序对传输的可靠性要求不高,但是对传输速度和延迟要求较高时,可以用UDP协议来替代TCP协议在传输层控制数据的转发。
UDP适合于实时数据传输,如语音和视频通信,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。例如:我们在看视频的时候偶尔丢一两个包也不影响体验。
常用的使用UDP协议包括:TFTP、SNMP、NFS、DNS、BOOTP。
使用Socket套接字实现UDP通信
创建UDPClient
Udp没有服务端和客户端一说,直接点对点发送,不用建立连接即可直接发送,代码也非常简单,C#中可以使用Socket创建udp套接字
发送消息
Socket client;
private void Form1_Load(object sender, EventArgs e)
{
// 1、创建UDP套接字
client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 2、绑定本地端口(开启本地udp客户端)
client.Bind(new IPEndPoint(IPAddress.Any, 8000));
}
private void button1_Click(object sender, EventArgs e)
{
// 发送数据到 192.168.102.12:8989
client.SendTo(new byte[] {1,2,3}, new IPEndPoint(IPAddress.Parse("192.168.102.12"), 8989));
}
接收消息
Socket soc;
private void Form1_Load(object sender, EventArgs e)
{
// 1、创建UDP套接字
client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 2、绑定本地端口(开启本地udp客户端),因为我本地就是192.168.102.12,所以这里写Any也可以,上面的发送将会发送到这里
client.Bind(new IPEndPoint(IPAddress.Any, 8989));
// 3、分线程死循环接收数据
Task.Run(() =>
{
while (true)
{
byte[] buffer = new byte[20]; // 接收数据的数组
EndPoint fromIp = new IPEndPoint(IPAddress.None, 0); // 记录该数据由哪个地址发送
soc.ReceiveFrom(buffer, 0, ref fromIp); // 接收数据
IPEndPoint ip = fromIp as IPEndPoint;
Console.WriteLine(ip.Address + ":" + ip.Port + "收到:" + Encoding.UTF8.GetString(buffer));
}
});
}
UDP组播
上面例子中发送数据只能向单个端发送,UDP支持组播
组播首先由一个用户申请一个组播组,这个组播组被维护在路由器中,其他用户申请加入组播组,这样当一个用户向组内发送消息时,路由器将消息转发给组内的所有成员。
UDP组播的基本步骤
1. 建立socket
2. socket和端口绑定
3. 加入一个组播组
4. 通过sendto / recvfrom进行数据的收发
5. 关闭socket
组播需要使用组播地址,在 IPv4 中它的范围从 224.0.0.0 到 239.255.255.255,并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类
224.0.0.0 ~ 224.0.0.255: 局部链接多播地址:是为路由协议和其它用途保留的地址,只能用于局域网中,路由器是不会转发的地址 224.0.0.0 不能用,是保留地址224.0.1.0 ~ 224.0.1.255: 为用户可用的组播地址(临时组地址),可以用于 Internet 上的。224.0.2.0 ~ 238.255.255.255: 用户可用的组播地址(临时组地址),全网范围内有效239.0.0.0 ~ 239.255.255.255: 为本地管理组播地址,仅在特定的本地范围内有效
// 1、创建UDP套接字
client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 2、绑定本地端口
client.Bind(new IPEndPoint(IPAddress.Any, 60000));
// 3、添加到组,组的ip为235.0.0.0
client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("235.0.0.0")));
// 发送数据到组,路由器将会转发给所有加入了该组的updClient, 并且对应的udpClient端口必须是10000
byte[] buffer = Encoding.UTF8.GetBytes("测试");
udpClient.Send(buffer, buffer.Length, new IPEndPoint(IPAddress.Parse("235.0.0.0"), 10000));
接收之前也只需要加上一句`client.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("235.0.0.0")));`保持和发送端在同一个组内即可
如下
// 创建UDP套接字
Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 2、绑定本地端口(要和发送者发送时的目标端口一致)
soc.Bind(new IPEndPoint(IPAddress.Any, 10000));
// 3、添加到组,组的ip为要和发送者加入的组一致
soc.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("235.0.0.0")));
// 4、启动线程接受消息即可
Task.Run(() =>
{
while (true)
{
byte[] buffer = new byte[20];
EndPoint fromIp = new IPEndPoint(IPAddress.None, 0);
soc.ReceiveFrom(buffer, 0, ref fromIp);
IPEndPoint ip = fromIp as IPEndPoint;
Console.WriteLine(ip.Address + ":" + ip.Port + "收到:" + Encoding.UTF8.GetString(buffer));
}
});
以上内容部分借鉴于网络,如有侵权请联系本人删除!!!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)