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
相关产品推荐
相关产品推荐

