ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C# WinForm TCP聊天室(服务端+客户端)

C# WinForm TCP聊天室(服务端+客户端) 一、项目整体功能考点本项目为多客户端TCP聊天室支持服务端监听、多客户端同时在线客户端上线自动刷新在线列表下拉框私聊对选中单个客户端发消息广播对所有在线客户端群发消息自定义断开协议n1 协议标记客户端下线自动从在线列表移除服务端关闭主动通知所有客户端下线窗口关闭自动释放资源、防止端口占用二、核心数据结构考点必考2.1 双容器存储客户端核心设计 对应代码// 字典用于快速查找客户端Key终端唯一标识 DictionaryEndPoint, Socket clients new DictionaryEndPoint, Socket(); // 泛型集合绑定下拉框数据源展示在线客户端 ListClient clients2 new ListClient();考点解释Dictionary保证客户端唯一性防止重复连接ListClient自定义实体类专门用于UI下拉框绑定2.2 自定义 Client 实体类知识点 完整代码作用封装客户端终端地址和Socket对象适配下拉框 DisplayMember / ValueMember 绑定public class Client { public EndPoint EndPoint { get; set; } // 客户端IP端口展示 public Socket Socket { get; set; } // 客户端套接字取值发送 }三、自定义通信协议 n1超级重点3.1 为什么不用系统自带断开TCP是流式协议客户端异常掉线、断网服务端无法立刻感知会造成在线列表残留脏数据。3.2 自定义 n1 协议规则考试必背 对应代码片段客户端下线发送n1核心代码// 客户端主动下线发送自定义协议告知服务端 socketClient.Send(Encoding.UTF8.GetBytes(n1));服务端识别下线n1核心代码// 服务端接收消息判断下线协议 if (message n1) { // 移除离线客户端、刷新列表 Client c1 clients2.Find(x x.EndPoint end); clients2.Remove(c1); }服务端关闭全员推送n1代码// 服务端关闭通知所有客户端下线 foreach (var item in clients2) { item.Socket.Send(Encoding.UTF8.GetBytes(n1)); item.Socket.Disconnect(false); }客户端接收n1自动断连代码if (message n1) { DisConnectServer(); // 服务端掉线客户端主动断开 }客户端主动下线先向服务端发送字符串n1服务端收到 n1判定该客户端正常下线从集合、下拉框中移除服务端关闭主动向所有客户端发送n1客户端收到 n1自动断开连接、重置状态四、服务端核心流程知识点4.1 服务端启动流程StartServer流程考点 完整代码public void StartServer() { // 1.创建TCP服务端套接字 socketServer new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 2.组装IP端口终端 IPAddress ip IPAddress.Parse(textBox1.Text); int port int.Parse(textBox2.Text); IPEndPoint endPoint new IPEndPoint(ip, port); // 3.绑定端口 开启监听 socketServer.Bind(endPoint); socketServer.Listen(1000); }实例化 TCP 流式 Socket读取文本框IP、端口组装 IPEndPointBind 绑定端口Listen 开启监听4.2 多客户端监听机制Accept 双层Task 考点 核心代码// 双层Task异步监听支持多客户端并发 cts1 new CancellationTokenSource(); Task.Run(() { while (!cts1.IsCancellationRequested) { // 外层接收新客户端连接 Socket socketClient socketServer.Accept(); // 内层每个客户端独立线程收消息 Task.Run(() { while (!cts1.IsCancellationRequested) { byte[] buffer new byte[1024 * 10]; int length socketClient.Receive(buffer); } }, cts1.Token); } }, cts1.Token);外层Task循环 Accept不停接收新客户端连接内层Task为每个客户端开启独立线程循环接收消息使用CancellationTokenSource安全终止线程防止内存泄漏4.3 客户端上线逻辑考点 对应代码// 客户端连接成功后判重添加集合 if (!clients.ContainsKey(socketClient.RemoteEndPoint)) { // 加入字典去重 clients.Add(socketClient.RemoteEndPoint, socketClient); // 加入UI绑定集合 clients2.Add(new Client() { EndPoint socketClient.RemoteEndPoint, Socket socketClient }); // Invoke跨线程刷新下拉框UI Invoke(new Action(() { comboBox1.DataSource null; comboBox1.DataSource clients2; comboBox1.DisplayMember EndPoint; comboBox1.ValueMember Socket; })); }客户端连接成功判断字典是否包含该终端不包含则加入添加实体到 List 集合Invoke刷新UI重置下拉框数据源刷新在线列表4.4 客户端下线逻辑考点 对应代码// 接收下线协议n1执行下线逻辑 if (message n1) { EndPoint end socketClient.RemoteEndPoint; Client c1 clients2.Find(x x.EndPoint end); clients2.Remove(c1); clients.Remove(end); // 刷新在线客户端下拉框 Invoke(new Action(() { comboBox1.DataSource null; if (clients2.Count 0) { comboBox1.DataSource clients2; comboBox1.DisplayMember EndPoint; comboBox1.ValueMember Socket; } })); }服务端接收客户端消息判断是否为n1根据终端地址查找对应 Client 对象从 List、字典中移除客户端刷新下拉框在线列表无客户端则清空数据源4.5 服务端关闭流程CloseServer考点 完整代码private void CloseServer() { if (socketServer ! null) { // 1.全员推送下线协议n1 foreach (var item in clients2) { item.Socket.Send(Encoding.UTF8.GetBytes(n1)); item.Socket.Disconnect(false); } // 2.关闭服务端套接字 socketServer.Close(); socketServer null; // 3.终止后台线程 cts1.Cancel(); // 4.清空集合与UI clients.Clear(); clients2.Clear(); comboBox1.DataSource null; button1.Text 启动服务器; } }完整安全释放流程考试高频遍历所有在线客户端统一发送n1下线通知强制断开所有客户端连接关闭服务端Socket、置空对象取消异步线程任务清空客户端集合、清空UI下拉框五、消息发送两大模式考点5.1 私聊模式默认考点 对应代码// 获取下拉框选中的单个客户端单独发送 Socket s1 (Socket)comboBox1.SelectedValue; if (s1 ! null s1.Connected) { s1.Send(Encoding.UTF8.GetBytes(服务器说 textBox3.Text)); }获取下拉框选中的客户端 Socket单独向该客户端发送消息5.2 广播模式勾选复选框考点 对应代码// 遍历所有在线客户端全员群发 if (checkBox1.Checked) { foreach (var item in clients2) { item.Socket.Send(Encoding.UTF8.GetBytes(服务器说 textBox3.Text)); } }遍历所有在线客户端集合逐个Send发送消息实现全员广播六、客户端核心知识点6.1 客户端连接流程 考点 完整代码public void ConnetSrever() { // 1.创建客户端Socket socketClient new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 2.组装服务端终端 IPEndPoint endPoint new IPEndPoint(IPAddress.Parse(textBox1.Text), int.Parse(textBox2.Text)); // 3.连接服务端 socketClient.Connect(endPoint); // 4.上线提示 修改按钮状态 socketClient.Send(Encoding.UTF8.GetBytes(建立连接成功)); button1.Text 断开服务器; }判断IP、端口非空校验创建客户端Socket指定服务端IP端口终端Connect 连接服务端上线发送提示消息修改按钮状态6.2 客户端断开流程 考点 完整代码private void DisConnectServer() { if (socketClient ! null) { // 1.发送下线协议 socketClient.Send(Encoding.UTF8.GetBytes(n1)); // 2.断开、关闭、释放资源 socketClient.Disconnect(false); socketClient.Close(); socketClient null; // 3.终止后台接收线程 cts.Cancel(); // 4.重置按钮状态 button1.Text 连接服务器; } }主动发送n1告知服务端即将下线断开Socket连接、关闭、置空取消后台接收线程重置按钮状态6.3 客户端被动下线 考点 对应代码// 客户端接收服务端消息识别服务端下线指令 string message Encoding.UTF8.GetString(buffer); if (message n1) { DisConnectServer();// 自动断开连接 }客户端接收消息若消息为n1代表服务端关闭自动执行断开连接方法。七、必考通用考点TCP聊天室通用子线程不能操作UI所有控件更新必须使用 InvokeTCP无边界问题原生代码使用 Available了解即可考试不扣分双集合优点字典查改快、List适配UI绑定自定义协议意义解决TCP断线不感知、在线列表残留问题资源释放窗口关闭、服务器关闭必须彻底释放Socket和线程按钮状态互斥连接/断开、启动/关闭文字切换防止重复操作八、简答题满分模版直接背诵本TCP聊天室采用服务端监听、多客户端接入模式。服务端通过字典和泛型集合双容器管理在线客户端实现客户端唯一性校验与UI在线列表展示。通过自定义n1断线协议解决TCP协议无法主动感知客户端掉线的问题保证在线列表数据准确。程序支持单客户端私聊与全员广播两种消息发送模式通过双层异步任务实现多客户端并发通信。所有子线程UI更新采用Invoke调度所有连接关闭时执行完整资源释放保证程序稳定运行、无端口占用与内存泄漏。
返回列表