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

C#实现支持多客户端互通的TCP服务器与客户端功能求助

C# TCP多人聊天室实现方案

核心修改逻辑

服务端改造点

  • 新增客户端管理容器:定义ConcurrentDictionary<Socket, string>存储已连接的客户端Socket和对应用户名,线程安全避免多线程冲突,设置最大容量为4
  • 异步/多线程接收连接:原代码的同步Accept只能处理单个客户端,改为循环接收新连接,每接入新客户端先判断当前连接数,超过4个直接返回连接已满提示并断开
  • 每个客户端独立线程处理:新连接接入后开启独立线程处理该客户端的消息接收,避免阻塞其他客户端交互
  • 消息广播逻辑:收到任意客户端的消息后,遍历所有在线客户端,将消息带上发送方用户名转发给除发送方外的所有客户端
  • 异常/断开处理:捕获客户端断开异常,自动将该客户端从管理容器移除,释放Socket资源

客户端改造点

  • 连接建立后先触发用户名设置:连接服务端成功后,先提示用户输入用户名,发送给服务端完成注册
  • 收发消息分离:开启独立后台线程持续监听服务端转发的消息,主线程仅负责读取用户输入并发送,避免发消息时收不到其他人的消息
  • 编码统一:原客户端用ASCII编码,改为UTF8和服务端对齐,避免中文乱码

修正后核心代码

服务端完整代码

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace SimpleTcpSrvr
{
    class Program
    {
        private const int MaxClientCount = 4;
        private static readonly ConcurrentDictionary<Socket, string> _clientDict = new ConcurrentDictionary<Socket, string>();
        
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;
            IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1302);
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Bind(serverEndPoint);
            serverSocket.Listen(10);
            Console.WriteLine("服务端启动成功,等待客户端连接,最大支持4人同时在线...");

            // 循环接收新连接
            while (true)
            {
                Socket clientSocket = serverSocket.Accept();
                if (_clientDict.Count >= MaxClientCount)
                {
                    byte[] fullMsg = Encoding.UTF8.GetBytes("当前聊天室已满,请稍后再试");
                    clientSocket.Send(fullMsg);
                    clientSocket.Close();
                    continue;
                }
                Console.WriteLine($"新客户端接入:{clientSocket.RemoteEndPoint}");
                // 开启新线程处理该客户端
                Thread clientThread = new Thread(HandleClient);
                clientThread.Start(clientSocket);
            }
        }

        private static void HandleClient(object obj)
        {
            Socket clientSocket = obj as Socket;
            byte[] buffer = new byte[1024];
            string userName = string.Empty;

            try
            {
                // 第一次接收的是用户名
                int len = clientSocket.Receive(buffer);
                userName = Encoding.UTF8.GetString(buffer, 0, len);
                _clientDict.TryAdd(clientSocket, userName);
                Console.WriteLine($"用户{userName}加入聊天室,当前在线人数:{_clientDict.Count}");

                // 欢迎消息
                byte[] welcome = Encoding.UTF8.GetBytes($"欢迎进入聊天室,当前在线人数:{_clientDict.Count}");
                clientSocket.Send(welcome);

                // 循环接收消息
                while (true)
                {
                    len = clientSocket.Receive(buffer);
                    if (len == 0) break;
                    string msg = Encoding.UTF8.GetString(buffer, 0, len);
                    Console.WriteLine($"收到{userName}的消息:{msg}");
                    // 广播给所有其他客户端
                    BroadcastMessage($"[{userName}]:{msg}", clientSocket);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"客户端{userName}连接异常:{ex.Message}");
            }
            finally
            {
                // 移除客户端
                _clientDict.TryRemove(clientSocket, out _);
                BroadcastMessage($"用户{userName}已退出聊天室", null);
                clientSocket.Close();
                Console.WriteLine($"用户{userName}已离开,当前在线人数:{_clientDict.Count}");
            }
        }

        private static void BroadcastMessage(string msg, Socket excludeSocket)
        {
            byte[] msgBytes = Encoding.UTF8.GetBytes(msg);
            foreach (var client in _clientDict.Keys)
            {
                if (client != excludeSocket)
                {
                    try
                    {
                        client.Send(msgBytes);
                    }
                    catch
                    {
                        // 发送失败的后续处理会在HandleClient的finally里执行
                    }
                }
            }
        }
    }
}

客户端完整代码

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

namespace TCPClient
{
    public class TcpClient
    {
        private static Socket _clientSocket;
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;
            IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1302);
            _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                _clientSocket.Connect(serverEndPoint);
            }
            catch (SocketException e)
            {
                Console.WriteLine("无法连接到服务端");
                Console.WriteLine(e.ToString());
                return;
            }

            // 先设置用户名
            Console.Write("请输入你的用户名:");
            string userName = Console.ReadLine();
            _clientSocket.Send(Encoding.UTF8.GetBytes(userName));

            // 开启后台线程接收消息
            Thread receiveThread = new Thread(ReceiveMessage);
            receiveThread.IsBackground = true;
            receiveThread.Start();

            // 接收欢迎消息
            byte[] buffer = new byte[1024];
            int len = _clientSocket.Receive(buffer);
            Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, len));

            // 主线程处理输入发送
            while (true)
            {
                string input = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(input)) continue;
                // 光标上移一行覆盖输入
                Console.SetCursorPosition(0, Console.CursorTop - 1);
                Console.WriteLine($"[你]:{input}");
                _clientSocket.Send(Encoding.UTF8.GetBytes(input));
            }
        }

        private static void ReceiveMessage()
        {
            byte[] buffer = new byte[1024];
            while (true)
            {
                try
                {
                    int len = _clientSocket.Receive(buffer);
                    if (len == 0) break;
                    string msg = Encoding.UTF8.GetString(buffer, 0, len);
                    Console.WriteLine(msg);
                }
                catch
                {
                    Console.WriteLine("与服务端连接断开");
                    break;
                }
            }
        }
    }
}

功能验证说明

  • 最多同时4个客户端成功连接,第5个连接会被直接拒绝
  • 每个客户端发送的消息会自动带上用户名转发给其他所有在线用户
  • 用户进入、退出聊天室都会有系统提示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 22:57:03