WPF异步UDP聊天程序双向通信异常问题求助
问题原因分析
你的UDP聊天程序出现"后发送消息的程序仅能发送、接收失效"的核心问题在于接收端复用了被修改的IPEndPoint对象:
- 类成员
endPoint初始化为IPAddress.Any,用于监听所有来源的消息 - 第一次调用
EndReceive时,该对象会被自动填充为发送方的具体端点(IP+随机端口) - 后续调用
StartListening时,依然复用这个已被修改的endPoint,导致接收端只能监听来自该特定端点的消息,无法接收其他来源的消息
此外,发送逻辑中多余的ReuseAddress设置也可能引发端口冲突风险。
修复方案
1. 重构接收逻辑,每次监听使用新的IPEndPoint
删除类成员endPoint,在每次启动监听时创建新的IPEndPoint(IPAddress.Any, SERVERPORT),并通过BeginReceive的AsyncState参数传递给回调函数。
2. 移除发送逻辑中多余的端口复用设置
发送端无需设置ReuseAddress,系统会自动分配随机端口发送消息。
3. 优化窗口关闭逻辑,避免资源泄漏
关闭程序时先释放UDP客户端和线程资源,再关闭窗口。
修改后的完整代码
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows; using System.Windows.Dispatcher; namespace NetworkFinal { public enum Type { Client, Server } public partial class MainWindow : Window { private const int SERVERPORT = 9000; private Type type = Type.Server; private Thread hThread; private UdpClient client; private IAsyncResult asyncResult; public MainWindow() { InitializeComponent(); } private void btnSend_Click(object sender, RoutedEventArgs e) { string ip = IPTextBox.Text; string message = SendTextBox.Text; byte[] bytesHeader = Encoding.UTF8.GetBytes(type == Type.Server ? "S" : "C"); byte[] bytesMessage = Encoding.UTF8.GetBytes(message); byte[] bytes = new byte[bytesHeader.Length + bytesMessage.Length]; bytesHeader.CopyTo(bytes, 0); bytesMessage.CopyTo(bytes, bytesHeader.Length); try { using (UdpClient sendClient = new UdpClient()) { IPEndPoint targetEndPoint = new IPEndPoint(IPAddress.Parse(ip), SERVERPORT); sendClient.Send(bytes, bytes.Length, targetEndPoint); PrintChat("나: " + message); SendTextBox.Text = string.Empty; } } catch (Exception ex) { PrintConsole(ex.Message); } } private void btnConnect_Click(object sender, RoutedEventArgs e) { hThread = new Thread(ReceiveThreadFunc); hThread.Start(); } private void btnChange_Click(object sender, RoutedEventArgs e) { if (type == Type.Server) { type = Type.Client; TypeLabel.Content = "클라이언트"; } else { type = Type.Server; TypeLabel.Content = "서버"; } } private void btnClose_Click(object sender, RoutedEventArgs e) { // 释放UDP资源 if (client != null) { client.Close(); client = null; } // 终止线程 if (hThread != null && hThread.IsAlive) { hThread.Abort(); } Close(); } private void ReceiveThreadFunc() { try { if (client != null) throw new Exception("UDP 소켓이 이미 생성되어 있습니다."); client = new UdpClient(); client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); client.ExclusiveAddressUse = false; client.Client.Bind(new IPEndPoint(IPAddress.Any, SERVERPORT)); PrintConsole(string.Format("Binding Port {0}. Start Listening...", SERVERPORT)); StartListening(); } catch (Exception ex) { PrintConsole(ex.Message); } } private void StartListening() { // 每次创建新的端点,监听所有来源 IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Any, SERVERPORT); asyncResult = client.BeginReceive(Receive, listenEndPoint); } private void Receive(IAsyncResult ar) { if (client == null) return; try { // 从AsyncState获取监听端点 IPEndPoint remoteEndPoint = (IPEndPoint)ar.AsyncState; byte[] bytes = client.EndReceive(ar, ref remoteEndPoint); string message = Encoding.UTF8.GetString(bytes, 0, bytes.Length); if (isValidMessage(message)) { message = message.Substring(1); PrintChat("상대: " + message); } // 继续监听下一条消息 StartListening(); } catch (Exception ex) { PrintConsole(ex.Message); } } private bool isValidMessage(string message) { if (type == Type.Server) { return message[0].Equals('C'); } else { return message[0].Equals('S'); } } private void PrintChat(string message) { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate { ChatTextBlock.Text += message; ChatTextBlock.Text += "\n"; })); } private void PrintConsole(string message) { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate { ConsoleTextBlock.Text += message; ConsoleTextBlock.Text += "\n"; })); } } }
验证步骤
- 运行两个程序实例,分别设置为服务器和客户端
- 点击两个程序的「连接」按钮绑定端口
- 先发送消息的程序和后发送的程序均能正常收发消息
内容的提问来源于stack exchange,提问作者devhante
相关产品推荐
相关产品推荐

