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

C# TCP Server无法响应客户端断开连接问题求助

问题分析与解决方案

你的服务器无法检测客户端断开,核心问题在于**TcpClient.Connected属性无法实时反映连接状态**——它仅记录最后一次IO操作的结果,不会主动探测连接是否已断开。同时你的循环逻辑只在有数据可读时执行操作,客户端断开时不会触发任何IO操作,导致循环一直卡在while (client.Connected)里。

核心修复点

  • 用NetworkStream.Read()的返回值判断连接状态:当Read返回0时,表示客户端已断开连接
  • 确保UI操作的线程安全性(原代码中lbl_ClientText.Text = msg未使用Invoke,会引发跨线程异常)
  • 维护客户端计数,避免多客户端连接时状态显示混乱
  • 使用using语句自动释放TcpClient和NetworkStream资源,无需手动调用Close()

修改后的完整代码

using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace dwkTCPServerAndroidTablet
{
    public partial class Form1 : Form
    {
        private bool isServerRunning = false;
        private Thread serverThread = null;
        private const int port = 6000;
        private int connectedClientCount = 0; // 维护连接的客户端数量
        private TcpListener listener = null;
        private readonly object clientCountLock = new object(); // 线程锁,保证计数操作安全

        public Form1()
        {
            InitializeComponent();
        }

        private void btn_StartServer_Click(object sender, EventArgs e)
        {
            connectedClientCount = 0;
            serverThread = new Thread(BeginServer)
            {
                IsBackground = true
            };
            serverThread.Start();
            isServerRunning = true;
        }

        private void BeginServer()
        {
            Invoke((MethodInvoker)delegate
            {
                btn_StartServer.BackColor = Color.Red;
                lbl_ServerStatus.Text = "Server has Started";
                UpdateClientStatusLabel();
            });

            listener = new TcpListener(IPAddress.Any, port);
            listener.Start();

            while (isServerRunning)
            {
                try
                {
                    var newClient = listener.AcceptTcpClient();
                    // 原子操作更新客户端计数
                    lock (clientCountLock)
                    {
                        connectedClientCount++;
                    }
                    // 启动客户端处理线程
                    var clientThread = new Thread(HandleClient)
                    {
                        IsBackground = true
                    };
                    clientThread.Start(newClient);
                    // 更新UI显示
                    Invoke((MethodInvoker)UpdateClientStatusLabel);
                }
                catch (SocketException)
                {
                    // 服务器停止时AcceptTcpClient会抛出异常,直接退出循环
                    break;
                }
            }
            listener.Stop();
        }

        private void HandleClient(object clientObj)
        {
            using var client = (TcpClient)clientObj;
            using var stream = client.GetStream();
            var buffer = new byte[1024];

            try
            {
                int bytesRead;
                // 循环读取数据,Read返回0表示客户端断开
                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    string msg = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                    // 跨线程更新UI
                    Invoke((MethodInvoker)delegate
                    {
                        lbl_ClientText.Text = msg;
                    });
                }
            }
            catch (SocketException)
            {
                // 客户端异常断开时捕获
            }
            finally
            {
                // 原子操作减少客户端计数
                lock (clientCountLock)
                {
                    connectedClientCount--;
                }
                // 更新UI显示
                Invoke((MethodInvoker)UpdateClientStatusLabel);
            }
        }

        private void UpdateClientStatusLabel()
        {
            if (connectedClientCount == 0)
            {
                lbl_ClientStatus.Text = "No Clients! ...";
            }
            else
            {
                lbl_ClientStatus.Text = $"Connected Clients: {connectedClientCount}";
            }
        }
    }
}

关键修改说明

  1. 连接状态判断:用stream.Read() > 0替代client.Connected,当客户端正常断开或异常断开时,Read会返回0或抛出异常,从而退出循环。
  2. 线程安全的客户端计数:用lock保证connectedClientCount的增减操作是原子的,避免多线程下的计数错误。
  3. 自动资源释放:使用using语句包裹TcpClient和NetworkStream,无需手动调用Close(),资源会在代码块结束时自动释放。
  4. 统一UI更新逻辑:提取UpdateClientStatusLabel方法,统一处理客户端状态显示,避免多客户端连接时的状态覆盖问题。
  5. 异常处理:捕获SocketException处理服务器停止或客户端异常断开的情况,避免程序崩溃。

内容的提问来源于stack exchange,提问作者dwk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 19:03:04