首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# UDP 點對點通訊完整實作 (UdpClient)

     編輯:關於C#

UDP 特性回顧

  • **無連線**、不可靠、無序、無流量控制
  • **低延遲、低開銷**,適合即時通訊、廣播、遊戲、串流
  • **無明確客戶端/伺服器**,雙方皆可收發 (Peer-to-Peer)

核心類別:UdpClient

封裝 SocketType.Dgram, ProtocolType.Udp,提供簡化 API:Send, Receive, JoinMulticastGroup。

完整 P2P 聊天範例 (WinForms)


public partial class ChatForm : Form
{
    private UdpClient _udp;
    private IPEndPoint _remoteEp;
    private Thread _listenThread;

    public ChatForm()
    {
        InitializeComponent();
        _udp = new UdpClient(8888); // 綁定本地埠 8888
        CheckForIllegalCrossThreadCalls = false; // 簡化跨執行緒 UI (教學用,生產請用 Invoke)
    }

    private void btnSend_Click(object sender, EventArgs e)
    {
        if (!IPAddress.TryParse(txtRemoteIP.Text, out var ip)) { MessageBox.Show("IP 格式錯誤"); return; }
        _remoteEp = new IPEndPoint(ip, 8888);

        if (_listenThread == null || !_listenThread.IsAlive)
        {
            _listenThread = new Thread(Listen) { IsBackground = true };
            _listenThread.Start();
        }

        byte[] data = Encoding.UTF8.GetBytes(txtMessage.Text);
        _udp.Send(data, data.Length, _remoteEp);
        lstMessages.Items.Add($"Me: {txtMessage.Text}");
        txtMessage.Clear();
    }

    private void Listen()
    {
        try
        {
            while (true)
            {
                IPEndPoint senderEp = null;
                byte[] data = _udp.Receive(ref senderEp); // 封鎖等待
                string msg = Encoding.UTF8.GetString(data);
                lstMessages.Items.Add($"{senderEp}: {msg}");
            }
        }
        catch (ThreadAbortException) { }
        catch (Exception ex) { MessageBox.Show($"Listen error: {ex.Message}"); }
    }

    private void btnClear_Click(object sender, EventArgs e) => lstMessages.Items.Clear();

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _listenThread?.Abort(); // 簡單粗暴,生產請用 CancellationToken
            _udp?.Close();
            components?.Dispose();
        }
        base.Dispose(disposing);
    }
}

UdpClient 關鍵方法

方法用途參數
Send(byte[], int, IPEndPoint)發送資料緩衝區、長度、目標端點
Send(byte[], int, string, int)發送資料 (主機名)緩衝區、長度、主機、埠
Receive(ref IPEndPoint)接收資料 (封鎖)ref 回傳發送端端點
BeginSend / EndSend非同步發送 (APM)回調、狀態
BeginReceive / EndReceive非同步接收 (APM)回調、狀態
JoinMulticastGroup(IPAddress)加入多播群組多播位址 (如 239.0.0.1)
DropMulticastGroup(IPAddress)離開多播群組多播位址

多播 (廣播) 範例


var udp = new UdpClient();
udp.JoinMulticastGroup(IPAddress.Parse("239.255.0.1")); // 組播位址
// 發送至組播位址,所有加入該組的主機皆收到
udp.Send(data, data.Length, new IPEndPoint(IPAddress.Parse("239.255.0.1"), 9999));

Socket 直接使用 UDP (進階控制)


var sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.Bind(new IPEndPoint(IPAddress.Any, 8888));
// 設定 Socket 選項
sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); // 允許廣播
sock.SendTo(data, new IPEndPoint(IPAddress.Broadcast, 8888)); // 發送廣播

常見問題與解決

現代非同步寫法 (TAP)


public async Task SendAsync(string message, IPEndPoint target)
{
    byte[] data = Encoding.UTF8.GetBytes(message);
    await _udp.SendAsync(data, data.Length, target);
}

public async Task ListenAsync(CancellationToken ct)
{
    while (!ct.IsCancellationRequested)
    {
        var result = await _udp.ReceiveAsync(ct);
        string msg = Encoding.UTF8.GetString(result.Buffer);
        // 更新 UI 需 Marshal 到 UI 執行緒
        this.Invoke(() => lstMessages.Items.Add($"{result.RemoteEndPoint}: {msg}"));
    }
}

UDP 適合**高即時性、可容忍少量丟失**的場景;需可靠傳輸請用 TCP 或應用層可靠協定 (KCP, QUIC)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題原因解決
資料遺失/亂序UDP 本質不可靠應用層實作 ACK/重傳/序號 (如 KCP, RUDP, QUIC)
防火牆阻擋UDP 埠未開放開放雙向 UDP 埠
NAT 穿透失敗雙方皆在 NAT 後STUN/TURN/ICE 或中繼伺服器
大封包分片/丟失超過 MTU (通常 1500)應用層分片 < 1400 bytes,或啟用 PMTUD
跨執行緒 UI 例外Listen 執行緒直接操作控制項用 Invoke/BeginInvoke 或 SynchronizationContext