You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中NetworkStream收发消息失败,求服务器代码排查修复方案

问题原因分析

先帮你拆解下服务器代码里的核心问题:

  1. 监听后未接受客户端连接:你的Button5_Click里只启动了TcpListener,但没有调用AcceptTcpClient()(或异步版本)来接受客户端的连接请求,客户端即使发起连接,服务器也没建立对应的通信通道。
  2. 服务器逻辑混淆成客户端:Button6_Click里居然让服务器自己创建TcpClient去连接本地,这完全搞反了角色——服务器应该是等待客户端连接,然后通过已接受的连接来发送/接收消息,而不是自己当客户端去连。
  3. UI线程阻塞风险:AcceptTcpClient()是阻塞方法,如果直接在UI线程调用会卡住界面,必须放到后台线程处理。
  4. 缺少发送确认与流处理:发送消息后没有调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:27:26