UdpClient 類別提供 UDP 協定通訊封裝,優點是簡單易用、支援廣播與多點傳送;缺點是無連線、不保證送達、不保證順序,應用層需自行處理丟包與亂序。本文示範以多點廣播實作區域網路聊天室。
255.255.255.255,僅限本地網段,路由器不轉發。192.168.255.255,目標特定網路。224.0.0.2 ~ 239.255.255.255,僅加入群組的主機接收,適合跨子網或特定群組通訊。UdpClient 可發送多點廣播,但無法接收多點廣播(需用 Socket 綁定 IP_ADD_MEMBERSHIP 選項)。本範例為簡化示範,採用單一 UdpClient 同時收發至同一多點群組位址。
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
namespace WinUDPChat
{
public class FormChat : Form
{
private static UdpClient _client;
private const int ListenerPort = 8080;
private const int SenderPort = 8080;
private static readonly IPAddress GroupAddress = IPAddress.Parse("10.0.0.1"); // 多點群組位址
private Thread _listenThread;
private ListBox _listBoxMsg;
private TextBox _textBoxMsg;
private Button _btnSend;
public FormChat()
{
InitializeComponent();
}
private void InitializeComponent()
{
_listBoxMsg = new ListBox { Location = new Point(21, 22), Size = new Size(248, 136) };
_textBoxMsg = new TextBox { Location = new Point(80, 197), Size = new Size(200, 20) };
_btnSend = new Button { Text = "發送", Location = new Point(96, 234) };
_btnSend.Click += BtnSend_Click;
Controls.AddRange(new Control[] { _listBoxMsg, _textBoxMsg, _btnSend });
Text = "UDP 聊天室";
ClientSize = new Size(292, 273);
Load += FormChat_Load;
FormClosed += FormChat_Closed;
}
private void FormChat_Load(object sender, EventArgs e)
{
_client = new UdpClient(ListenerPort);
_client.JoinMulticastGroup(GroupAddress, 100); // TTL=100
_listenThread = new Thread(Listener);
_listenThread.IsBackground = true;
_listenThread.Start();
}
private void Listener()
{
IPEndPoint remoteEP = null;
var encoding = Encoding.UTF8;
try
{
while (true)
{
byte[] data = _client.Receive(ref remoteEP);
string msg = encoding.GetString(data);
// 必須在 UI 執行緒更新控制項
Invoke((Action)(() => _listBoxMsg.Items.Add(msg)));
}
}
catch (SocketException)
{
// Socket 關閉時會拋出,正常結束
}
}
private void BtnSend_Click(object sender, EventArgs e)
{
string msg = _textBoxMsg.Text;
if (string.IsNullOrEmpty(msg)) return;
byte[] buffer = Encoding.UTF8.GetBytes(msg);
IPEndPoint remoteEP = new IPEndPoint(GroupAddress, SenderPort);
_client.Send(buffer, buffer.Length, remoteEP);
_textBoxMsg.Clear();
}
private void FormChat_Closed(object sender, FormClosedEventArgs e)
{
try
{
_client?.DropMulticastGroup(GroupAddress);
_listenThread?.Abort();
_client?.Close();
}
catch { }
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new FormChat());
}
}
}
Control.Invoke。DropMulticastGroup、Close,並中止接收執行緒。