C#中NetworkStream收发消息失败,求服务器代码排查修复方案
问题原因分析
先帮你拆解下服务器代码里的核心问题:
- 监听后未接受客户端连接:你的
Button5_Click里只启动了TcpListener,但没有调用AcceptTcpClient()(或异步版本)来接受客户端的连接请求,客户端即使发起连接,服务器也没建立对应的通信通道。 - 服务器逻辑混淆成客户端:
Button6_Click里居然让服务器自己创建TcpClient去连接本地,这完全搞反了角色——服务器应该是等待客户端连接,然后通过已接受的连接来发送/接收消息,而不是自己当客户端去连。 - UI线程阻塞风险:
AcceptTcpClient()是阻塞方法,如果直接在UI线程调用会卡住界面,必须放到后台线程处理。 - 缺少发送确认与流处理:发送消息后没有调用
networkStream.Flush()确保数据被发送,也没有异常捕获来排查连接/发送失败的问题。
仅修改服务器的修复方案
下面是修复后的服务器代码,我保留了你的原有UI按钮逻辑,只修正核心通信部分:
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows.Forms; // 假设这是你的WinForm类 public partial class YourServerForm : Form { IPAddress ipadd = IPAddress.Parse("127.0.0.1"); Int32 port = 8192; private TcpListener _listener; private TcpClient _connectedClient; private NetworkStream _networkStream; // 后台线程用于监听,避免卡住UI private Thread _listenThread; public YourServerForm() { InitializeComponent(); // 窗体关闭时清理资源 this.FormClosing += (s, e) => { _networkStream?.Close(); _connectedClient?.Close(); _listener?.Stop(); _listenThread?.Abort(); }; } private void Button5_Click(object sender, EventArgs e) { try { _listener = new TcpListener(ipadd, port); _listener.Start(); MessageBox.Show("服务器已启动,等待客户端连接..."); // 启动后台线程监听客户端连接 _listenThread = new Thread(ListenForClients); _listenThread.IsBackground = true; _listenThread.Start(); } catch (Exception ex) { MessageBox.Show($"启动服务器失败:{ex.Message}"); } } private void ListenForClients() { try { // 持续监听客户端连接 while (true) { // 阻塞等待客户端连接 _connectedClient = _listener.AcceptTcpClient(); _networkStream = _connectedClient.GetStream(); // 回到UI线程提示连接成功 this.Invoke((MethodInvoker)delegate { MessageBox.Show("客户端已连接!"); }); } } catch (ThreadAbortException) { // 线程被终止时正常退出 } catch (Exception ex) { this.Invoke((MethodInvoker)delegate { MessageBox.Show($"监听出错:{ex.Message}"); }); } } private void Button6_Click(object sender, EventArgs e) { try { // 先检查是否有已连接的客户端 if (_connectedClient == null || !_connectedClient.Connected) { MessageBox.Show("没有已连接的客户端,请先等待客户端连接!"); return; } string message = textBox3.Text; if (string.IsNullOrEmpty(message)) { MessageBox.Show("请输入要发送的消息!"); return; } byte[] sendBytes = Encoding.ASCII.GetBytes(message); // 写入流并刷新确保数据发送 _networkStream.Write(sendBytes, 0, sendBytes.Length); _networkStream.Flush(); MessageBox.Show($"已发送消息:{message},字节数:{sendBytes.Length}"); } catch (Exception ex) { MessageBox.Show($"发送消息失败:{ex.Message}"); } } }
关键修改说明
- 新增后台监听线程:把
AcceptTcpClient()放到后台线程,避免阻塞UI界面,同时持续监听客户端连接。 - 修正服务器角色:移除了服务器自己连接本地的错误逻辑,改为等待客户端主动连接,通过
_connectedClient保存已建立的连接。 - 添加资源清理:在窗体关闭时关闭流、客户端和监听器,避免资源泄漏。
- 增加异常处理与状态检查:发送前检查客户端连接状态,捕获异常并提示,方便排查问题。
- 添加发送确认:调用
Flush()确保数据被立即发送,同时弹出提示确认发送成功。
这样修改后,你的客户端代码不需要改动,只要服务器启动后(点Button5),客户端连接上来,就能通过服务器的Button6发送消息给客户端了。
内容的提问来源于stack exchange,提问作者Hyo
相关产品推荐
相关产品推荐

