UDP协议通信

UDP(User Datagram Protocol,用户数据报协议)是一种网络传输协议,属于传输层(TCP/IP 协议族)。它的主要特点和在 C# 中的表现:

  • 无连接:发送方与接收方之间不建立连接,直接发送数据报(datagram)。
  • 不可靠:不保证到达、不保证顺序、不做重传或确认;丢包或乱序需由应用层处理。
  • 低开销、延迟小:相比 TCP 更轻量,适合实时性要求高但能容忍部分丢包的场景(语音、视频、在线游戏、广播/多播)。
  • 报文边界保留:UDP 按数据报发送/接收,接收端能知道每次发送的报文边界。

在 C# 中常用类与用法:

  • UdpClient:封装较高层次的 UDP 操作,提供 Send/Receive 和异步 SendAsync/ReceiveAsync,适合大多数场景。
  • Socket:底层套接字 API(SocketType.Dgram, ProtocolType.Udp),用于需要精细控制(多播、广播、Socket 选项、性能调优)时。
  • 基本流程:接收端 bind 到本地端口并调用 Receive/ReceiveAsync/ReceiveFromAsync;发送端可直接 Send/SendAsync/SendTo(通常无需先 bind)。

 

.xaml

<Window x:Class="StudyUdp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:StudyUdp"
        mc:Ignorable="d"
        Title="Udp(用socket实现)" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1.5*"></ColumnDefinition>
            <ColumnDefinition Width="4*"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <!--左边-->
        <Grid Background="Azure">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition Height="auto"></RowDefinition>

            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition ></ColumnDefinition>
                <ColumnDefinition ></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock  VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,5,5">本机主机地址</TextBlock>
            <TextBox x:Name="txtIP" Grid.Column="1" Width="150" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,5,5">127.0.0.1</TextBox>
            <TextBlock  Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Right"  Margin="0,0,5,5">本机主机端口</TextBlock>
            <TextBox x:Name="txtPort" Grid.Row="1" Grid.Column="1" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,5,5">8888</TextBox>

            <Button  x:Name="BtnOpen"  Grid.Row="5"  Grid.ColumnSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" 
           Margin="0,0,10,5" Click="BtnOpen_Click">打开</Button>

            <Button  x:Name="BtnClose"  Grid.Row="5"  Grid.ColumnSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" 
Margin="0,0,10,5" Visibility="Collapsed" Click="BtnClose_Click">关闭</Button>
        </Grid>

        <!--右边-->
        <Grid Grid.Column="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition Height="auto"></RowDefinition>
            </Grid.RowDefinitions>

            <RichTextBox Height="300" x:Name="txtShowContent"  VerticalScrollBarVisibility="Visible"></RichTextBox>

            <Grid Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2*"></ColumnDefinition>
                    <ColumnDefinition Width="1*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <StackPanel Grid.ColumnSpan="2" Orientation="Horizontal" >
                    <TextBlock Margin="0,0,5,0">接收方信息</TextBlock>
                    <TextBlock Margin="0,0,5,0">IP:</TextBlock>
                    <TextBox x:Name="txtRecIP" Text="127.0.0.1" Width="150" Margin="0,0,5,0"></TextBox>
                    <TextBlock Margin="0,0,5,0">端口:</TextBlock>
                    <TextBox x:Name="txtRecPort" Width="100"></TextBox>
                </StackPanel>

                <TextBox Height="80" x:Name="txtSendContent" Grid.Row="1"></TextBox>
                <Button Grid.Column="1" Grid.Row="1" x:Name="BtnSend" Click="BtnSend_Click">发送</Button>
            </Grid>
        </Grid>
    </Grid>
</Window>
View Code

.xaml.cs

using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static System.Net.Mime.MediaTypeNames;

namespace StudyUdp;

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    Socket client;
    public MainWindow()
    {
        InitializeComponent();
    }

    /// <summary>
    /// 打开
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void BtnOpen_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            #region 用socket实现
            client = new Socket(SocketType.Dgram, ProtocolType.Udp);
            string ip = txtIP.Text;
            int port = Convert.ToInt32(txtPort.Text);
            client.Bind(new IPEndPoint(IPAddress.Parse(ip), port));

            BtnOpen.Visibility = Visibility.Collapsed;
            BtnClose.Visibility = Visibility.Visible;

            AppendTxt("打开成功", Colors.Green);
            #endregion

            #region 接收信息
            Task.Run(async () =>
            {
                while (true)
                {
                    _ = Dispatcher.Invoke(async () =>
                    {
                        //1、不需要知道谁发的  2、需要知道是谁发的
                        byte[] recBytes = new byte[1024];
                        IPEndPoint ipEp = new IPEndPoint(IPAddress.Any, 0);
                        var result = await client.ReceiveFromAsync(recBytes, ipEp);
                        if (result.ReceivedBytes > 0)//有数据
                        {
                            string recMsg = Encoding.UTF8.GetString(recBytes);
                            AppendTxt($"来自{result.RemoteEndPoint}的信息:{recMsg}", Colors.Blue);
                        }
                    });

                    await Task.Delay(1000);
                }
            });
            #endregion
        }
        catch (Exception)
        {
            BtnOpen.Visibility = Visibility.Visible;
            BtnClose.Visibility = Visibility.Collapsed;

            AppendTxt("打开异常", Colors.Red);
        }
    }

    /// <summary>
    /// 关闭
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void BtnClose_Click(object sender, RoutedEventArgs e)
    {
        if (client != null)
        {
            client.Close();
            BtnOpen.Visibility = Visibility.Visible;
            BtnClose.Visibility = Visibility.Collapsed;

            AppendTxt("已关闭", Colors.Red);
        }
    }

    /// <summary>
    /// 发送
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void BtnSend_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            if (client != null)
            {
                string sendMsg = txtSendContent.Text;
                byte[] sendBytes = Encoding.UTF8.GetBytes(sendMsg);
                //1、发送给所有连接自己的Client  2、给指定的终端发送信息
                client.SendTo(sendBytes, new IPEndPoint(IPAddress.Parse(txtRecIP.Text), Convert.ToInt32(txtRecPort.Text)));

                AppendTxt($"发送信息:{sendMsg}", Colors.Black);

                #region 广播发送
                //string sendMsg = txtSendContent.Text;
                //byte[] sendBytes = Encoding.UTF8.GetBytes(sendMsg);
                ////1、发送给所有连接自己的Client  2、给指定的终端发送信息
                //client.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.Broadcast,true);
                ////client.SendTo(sendBytes, new IPEndPoint(IPAddress.Parse("192.168.0.255"), 9999));
                //client.SendTo(sendBytes, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 9999));
                //AppendTxt($"发送信息:{sendMsg}", Colors.Black);
                #endregion

            }
        }
        catch (Exception)
        {
            AppendTxt($"发送信息异常", Colors.Red);
        }

    }

    FlowDocument doc = new FlowDocument();

    /// <summary>
    /// 追加文本
    /// </summary>
    /// <param name="txt"></param>
    /// <param name="txtColor">文字颜色</param>
    private void AppendTxt(string txt, Color txtColor)
    {

        var p = new Paragraph(); // Paragraph 类似于 html 的 P 标签
        var r = new Run($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} {txt}"); // Run 是一个 Inline 的标签
        p.Inlines.Add(r);
        p.Foreground = new SolidColorBrush(txtColor);//设置字体颜色
        doc.Blocks.Add(p);
        txtShowContent.Document = doc;
        txtShowContent.ScrollToEnd();
    }


}

 

posted @ 2026-03-23 21:14  野码  阅读(2)  评论(0)    收藏  举报