目录

UDP协议

综上所述:

优点:

缺点:

UDP应用场景

使用Socket套接字实现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));
        }
    });

以上内容部分借鉴于网络,如有侵权请联系本人删除!!!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐