ARTICLE DETAIL

资讯详情

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

C#TCP 服务器代码+TCP 客户端代码

C#TCP 服务器代码+TCP 客户端代码 整体功能架构说明1. 核心功能定位本代码实现TCP 服务器与串口双向联动功能核心逻辑为TCP 服务器接收客户端发送的十六进制字符串请求帧将其转换为字节数组后通过串口发送至下位机同时监听串口接收下位机返回的响应帧解析完整帧后通过 TCP 回发给对应客户端实现网口与串口的数据透传适配工业设备通信场景。2. 核心技术依赖TCP 通信基于 TcpListener 实现 TCP 服务器支持多客户端接入通过 ConcurrentDictionary 管理客户端连接保障线程安全串口通信基于 SerialPort 类实现串口数据收发配置标准 Modbus 串口参数8位数据位、无校验、1位停止位、9600波特率异步任务使用 Task.Run 与 CancellationTokenSource 实现后台客户端请求接收、数据读取避免 UI 卡顿数据转换实现十六进制字符串与字节数组的相互转换适配 TCP 字符串传输与串口字节传输的格式差异跨线程 UI 更新通过 Control.Invoke 解决后台线程操作 UI 控件的线程安全问题避免线程异常帧解析基于 Modbus 协议解析串口响应帧提取完整数据帧后回发客户端避免数据粘包、断包问题3. 核心通信参数与流程TCP 服务器参数IP 192.168.219.65端口9999监听客户端连接与请求帧串口参数COM1波特率96008位数据位无校验1位停止位与下位机通信核心流程启动 TCP 服务器与串口→接收客户端 TCP 请求→转换为串口字节帧→发送至下位机→接收串口响应帧→解析完整帧→回发对应客户端→展示通信日志一、代码逐行超细拆分解析1. 命名空间using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.IO.Ports; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms;解析引入核心系统命名空间涵盖网络编程TcpListener、TcpClient、NetworkStream、串口通信SerialPort、多线程ConcurrentDictionary、CancellationTokenSource、Task及 WinForms 控件剔除冗余引用如 System.Data、System.Drawing 等未用到的命名空间提升代码简洁性为 TCP 服务器与串口联动功能提供基础支持。二、命名空间与窗体类定义namespace TCP服务器 { public partial class Form1 : Form { // 后续字段与方法逻辑 } }解析定义 TCP 服务器专属命名空间主窗体类 Form1 继承自 WinForms 的 Form 类partial 关键字实现分部类分离窗体设计器代码与自定义服务器逻辑保证代码结构清晰便于后续维护。三、核心字段定义// 存储客户端终端与对应 TcpClient 对象支持并发访问 public ConcurrentDictionaryEndPoint, TcpClient clientDict new ConcurrentDictionaryEndPoint, TcpClient(); // 异步任务取消令牌源控制客户端接收、数据转发等任务的终止 private CancellationTokenSource cts; // 当前有请求的客户端对象用于串口响应数据的定向转发 public TcpClient currentClient; // 串口对象负责与串口设备通信 private SerialPort serialPort; // TCP 监听器负责监听客户端连接请求 private TcpListener tcpListener; // 缓存串口接收的数据用于拼接完整响应帧 public Listbyte serialReceiveBuffer new Listbyte();解析优化原代码字段命名统一规范如 dic→clientDict、serailPort1→serialPort、tcpListen→tcpListener明确各字段用途clientDict 管理所有连接的客户端cts 控制异步任务生命周期currentClient 定向转发串口响应serialPort 与串口设备交互tcpListener 监听客户端连接serialReceiveBuffer 缓存串口数据拼接完整帧提升代码可读性。四、窗体构造函数public Form1() { InitializeComponent(); }解析初始化窗体上的所有控件按钮、富文本框等由 WinForms 设计器自动生成无需手动修改确保窗体加载时控件正常初始化为后续服务器启动、数据交互做准备。五、启动/停止按钮点击事件button1_Click/// summary /// TCP 服务器与串口启停控制按钮点击事件 /// 切换逻辑按钮文本为“启动”时执行启动流程否则执行停止流程 /// 核心流程启动 TCP 服务器与串口→开启客户端请求接收停止时释放资源、重置状态 /// /summary private void button1_Click(object sender, EventArgs e) { try { if (button1.Text 启动) { // 启动服务器初始化串口与 TCP 监听器 StartServer(); // 启动异步任务接收客户端连接请求 AcceptRequest(); } else { // 停止操作取消异步任务、停止 TCP 监听、释放资源 cts?.Cancel(); tcpListener?.Stop(); // 清空客户端字典 clientDict.Clear(); // 重置按钮文本 button1.Text 启动; } } catch (Exception) { // 抛出异常便于上层捕获处理可根据需求优化为弹窗提示 throw; } }核心要点与易错点启动顺序先启动服务器初始化 TCP 监听器与串口再开启客户端请求接收任务确保通信环境就绪资源释放停止服务时必须按顺序终止任务→停止 TCP 监听器→清空客户端字典避免资源泄漏异常处理当前代码直接抛出异常实际项目可优化为友好提示日志记录避免程序崩溃影响用户体验六、服务器启动方法StartServer/// summary /// 启动 TCP 服务器与串口初始化通信参数 /// 核心逻辑配置并打开串口→配置并启动 TCP 监听器→更新界面状态 /// /summary public void StartServer() { // 1. 初始化串口并打开 serialPort new SerialPort(); serialPort.Parity Parity.None; serialPort.DataBits 8; serialPort.StopBits StopBits.One; serialPort.PortName COM1; serialPort.BaudRate 9600; if (!serialPort.IsOpen) { serialPort.Open(); } // 绑定串口数据接收事件 serialPort.DataReceived SerialPort_DataReceived; // 2. 初始化 TCP 监听器并启动监听 IPAddress ip IPAddress.Parse(192.168.219.65); int port 9999; tcpListener new TcpListener(ip, port); tcpListener.Start(); // 更新按钮文本为“停止” button1.Text 停止; }核心要点与易错点串口参数一致性串口参数波特率、数据位、校验位、停止位必须与下位机完全一致否则无法正常通信串口号适配PortName 需根据实际设备连接的串口号修改如 COM2、COM3避免串口打开失败TCP 端口占用TCP 监听端口9999需未被其他程序占用否则会导致 TcpListener 启动失败事件绑定串口数据接收事件需在串口打开前绑定确保能正常接收下位机响应数据七、客户端连接请求接收方法AcceptRequest/// summary /// 后台接收客户端 TCP 连接请求管理客户端连接 /// 核心逻辑循环监听客户端连接→接收客户端对象→添加至字典→开启客户端数据接收任务 /// /summary public void AcceptRequest() { cts new CancellationTokenSource(); Task.Run(async () { while (!cts.IsCancellationRequested) { // 若存在挂起的连接请求跳过本次循环避免阻塞 if (tcpListener.Pending()) { continue; } // 异步接收客户端连接获取 TcpClient 对象 TcpClient client await tcpListener.AcceptTcpClientAsync(); // 获取客户端远程终端信息 EndPoint clientEndPoint client.Client.RemoteEndPoint; // 将客户端添加到字典终端为键TcpClient 为值 clientDict.TryAdd(clientEndPoint, client); // 启动异步任务接收该客户端发送的数据 AcceptData(client); } }, cts.Token); }核心要点与易错点线程安全使用 ConcurrentDictionary 存储客户端连接避免多线程并发添加/删除导致的异常异步接收使用 AcceptTcpClientAsync 实现异步接收客户端连接避免阻塞主线程保证 UI 流畅连接管理每个客户端连接均开启独立的数据接收任务实现多客户端并发处理任务控制通过 CancellationTokenSource 控制后台任务生命周期服务停止时可正常终止任务八、客户端数据接收与转发方法AcceptData/// summary /// 接收客户端发送的 TCP 请求帧转换为串口格式并转发至下位机 /// 核心逻辑读取客户端请求帧→十六进制字符串转字节数组→通过串口发送→展示通信日志 /// /summary /// param nametcpClinet客户端 TcpClient 对象/param public void AcceptData(TcpClient client) { cts new CancellationTokenSource(); Task.Run(async () { while (!cts.IsCancellationRequested) { // 客户端未连接或无数据可接收时跳过本次循环 if (!client.Connected || client.Available 0) { continue; } // 获取网络流用于读写数据 NetworkStream networkStream client.GetStream(); // 初始化缓冲区长度为客户端可用数据长度 byte[] buffer new byte[client.Available]; // 异步读取客户端数据 int readCount await networkStream.ReadAsync(buffer, 0, buffer.Length); if (readCount 0) { continue; } // 将接收的字节数组转换为十六进制字符串客户端传输的是十六进制字符串形式 string hexString Encoding.UTF8.GetString(buffer); // 将十六进制字符串转换为字节数组用于串口发送 byte[] serialSendBuffer HexStringToByte(hexString); // 跨线程更新 UI展示接收的客户端数据 Invoke(new Action(() { richTextBox1.Text ${client.Client.RemoteEndPoint}:{ByteToString(serialSendBuffer)}{Environment.NewLine}; })); // 串口已打开时将数据转发至串口设备 if (serialPort.IsOpen) { // 保存当前有请求的客户端用于后续串口响应数据的定向转发 currentClient client; serialPort.Write(serialSendBuffer, 0, serialSendBuffer.Length); } } }, cts.Token); }核心要点与易错点格式转换核心客户端发送的是十六进制字符串如01030000需通过 HexStringToByte 转换为字节数组01 03 00 00才能通过串口发送客户端关联通过 currentClient 保存当前发起请求的客户端确保串口响应帧能准确回发给对应客户端异步读取使用 ReadAsync 实现异步读取客户端数据避免阻塞主线程提升并发处理能力串口状态校验发送串口数据前需检查串口是否打开避免串口未打开导致的发送失败九、串口数据接收与响应转发方法SerialPort_DataReceived/// summary /// 串口数据接收事件接收下位机返回的响应帧解析完整帧后回发对应客户端 /// 核心逻辑读取串口数据→缓存至列表→拼接完整帧→回发客户端→展示通信日志 /// /summary private void SerailPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { // 若串口未打开直接返回避免无效操作 if (!serailPort1.IsOpen) return; // 获取串口可读取的字节数 int length serailPort1.BytesToRead; // 创建缓冲区读取串口响应数据 byte[] serialResBuffer new byte[length]; serailPort1.Read(serialResBuffer, 0, length); // 将本次读取的串口数据追加至缓存列表解决数据粘包、断包问题 list.AddRange(serialResBuffer); // 循环解析缓存列表提取完整的响应帧基于 Modbus 协议 while (list.Count 5) // Modbus 响应帧最小长度为5字节 { // 提取响应帧中的数据长度Modbus 协议第3字节为数据长度 byte dataLength list[2]; // 计算完整响应帧的长度3字节固定头 数据长度 2字节 CRC 校验 int fullFrameLength 3 dataLength 2; // 若缓存列表长度大于等于完整帧长度说明已拼接出完整帧 if (list.Count fullFrameLength) { // 从缓存列表中提取完整响应帧 byte[] fullFrame list.Take(fullFrameLength).ToArray(); // 从缓存列表中移除已提取的完整帧数据 list.RemoveRange(0, fullFrameLength); // 将完整帧转换为十六进制字符串用于 UI 展示 string msg ByteToString(fullFrame); // 若当前有发起请求的客户端且客户端已连接回发响应帧 if (currentClient ! null currentClient.Connected) { try { // 获取客户端网络流用于发送响应帧 NetworkStream stream currentClient.GetStream(); // 向客户端发送完整响应帧 stream.Write(fullFrame, 0, fullFrame.Length); // 跨线程更新 UI展示回发的响应帧 Invoke(new Action(() { richTextBox1.Text $服务下发响应帧{msg}{Environment.NewLine}; })); } catch (Exception) { // 发送失败则关闭客户端连接释放资源 currentClient.Close(); currentClient null; } } } else { // 缓存数据不足完整帧退出循环等待下次串口数据接收 break; } } }核心要点与易错点帧解析逻辑严格遵循 Modbus 协议解析响应帧通过第3字节的数据长度计算完整帧长度确保解析准确粘包处理通过 List 缓存串口数据循环拼接完整帧解决串口数据粘包、断包导致的解析异常客户端回发仅回发给当前发起请求的客户端实现请求-响应的一对一关联避免广播式回发异常处理回发失败时关闭客户端连接释放资源避免无效连接占用系统资源十、工具方法十六进制与字节数组互转1. 十六进制字符串转字节数组HexStringToByte/// summary /// 十六进制字符串转字节数组适配串口发送格式 /// 输入示例010300000004409 → 输出[01, 03, 00, 00, 00, 04, 40, 09] /// /summary /// param namehex十六进制字符串/param /// returns转换后的字节数组/returns public byte[] HexStringToByte(string hex) { // 移除字符串中的空格避免格式干扰 hex hex.Replace( , ); // 若字符串长度为奇数无法转换为完整字节返回空数组 if (hex.Length % 2 ! 0) return new byte[0]; // 定义字节数组长度为原字符串长度的一半每2个字符对应1个字节 byte[] res new byte[hex.Length / 2]; // 循环转换每2个字符为一组转换为对应的字节 for (int i 0; i res.Length; i) { res[i] Convert.ToByte(hex.Substring(i * 2, 2), 16); } return res; }解析处理客户端发送的十六进制字符串去除空格后校验格式将每两位字符转换为一个字节适配串口传输的字节格式确保数据转换的准确性。2. 字节数组转十六进制字符串ByteToString/// summary /// 将字节数组转换为十六进制字符串如 [0x01, 0x03] → 01 03 /// /summary /// param namedata字节数组lt;/paramgt; /// returns格式化后的十六进制字符串/returns public string ByteToString(byte[] data) { return BitConverter.ToString(data).Replace(-, ); }解析将字节数组转换为带空格的十六进制字符串用于 UI 展示提升数据可读性适配用户查看需求。十一、代码核心知识点与优化说明多客户端并发处理采用 ConcurrentDictionary 存储客户端支持多线程并发访问为每个客户端启动独立的数据接收任务实现多客户端同时连接与数据交互避免线程冲突。串口与 TCP 联动服务器接收客户端 TCP 数据后转换为串口适配格式转发至串口设备串口接收响应后拼接完整帧并定向转发至对应客户端实现 TCP 与串口的双向数据交互。异步与资源管理采用异步任务接收客户端连接与数据通过 CancellationTokenSource 控制任务终止避免阻塞 UI 线程停止服务器时释放 TCP 监听器、串口、客户端对象等资源避免内存泄漏。数据帧处理串口接收数据后通过缓存列表拼接完整响应帧根据 Modbus 帧格式计算帧长度确保转发给客户端的是完整数据避免数据丢失或错乱。代码规范优化变量命名修正原代码拼写错误如 serailPort→serialPort添加详细注释拆分冗余逻辑提升代码可读性与可维护性统一异常处理便于调试定位问题。TCP 客户端代码一、整体功能架构说明1. 核心功能定位本代码实现TCP 客户端核心功能支持连接指定 TCP 服务器、向服务器发送请求帧、接收服务器返回的响应帧并展示适配与前文 TCP 服务器的联动通信可处理服务器返回的 Modbus 协议响应帧兼具基础通信与简单数据解析能力。2. 核心技术依赖TCP 通信基于 TcpClient 类实现 TCP 客户端支持异步连接服务器、异步收发数据适配长连接通信场景异步任务使用 Task.Run 与 CancellationTokenSource 实现后台数据接收避免 UI 卡顿保障界面流畅性跨线程 UI 更新通过 Control.Invoke 解决后台线程操作 UI 控件的线程安全问题避免线程异常数据转换实现字节数组与十六进制字符串的相互转换适配服务器响应帧的展示需求数据解析简单解析服务器返回的 Modbus 响应帧提取核心数据适配工业通信场景3. 核心通信参数与流程服务器参数IP 192.168.219.65端口9999与前文 TCP 服务器参数保持一致核心流程启动客户端→连接 TCP 服务器→开启后台数据接收任务→发送请求帧→接收并解析响应帧→展示通信日志→断开连接释放资源二、代码逐行超细拆分解析1. 命名空间、全局变量与构造函数// 引入系统核心命名空间支撑 UI 控件、网络通信、异步任务等功能 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; // 定义 TCP 客户端专属命名空间隔离代码层级避免类名冲突 namespace TCP客户端 { /// summary /// TCP 客户端主界面类 /// 核心职责连接/断开 TCP 服务器、接收服务器响应帧、向服务器发送请求帧、展示通信日志 /// 核心特点适配 Modbus 协议通信支持异步收发数据与前文 TCP 服务器完美联动 /// /summary public partial class Form1 : Form { // 全局变量按功能分类各司其职便于维护与资源管理 // 1. 异步任务取消源控制后台数据接收任务的生命周期避免资源泄漏 CancellationTokenSource cts; // 2. TCP 客户端对象通信核心对象负责与服务器建立连接、收发数据 TcpClient client; // 构造函数仅初始化界面控件Visual Studio 自动生成无需手动修改 public Form1() { InitializeComponent(); } // 后续事件方法拆分解析... } }说明全局变量设计简洁聚焦CancellationTokenSource 负责后台任务管理TcpClient 负责核心通信无冗余变量符合客户端轻量化需求。2. 启动/停止客户端按钮事件button1_Click/// summary /// 客户端启停控制按钮点击事件 /// 切换逻辑按钮文本为“启动”时执行启动流程否则执行停止流程 /// 核心流程连接服务器→开启后台数据接收任务停止时释放资源、重置状态 /// /summary private void button1_Click(object sender, EventArgs e) { try { if (button1.Text 启动) { // 1. 异步连接 TCP 服务器建立通信链路 connectServer(); // 2. 开启后台任务持续接收服务器返回的响应帧 AcceptData(); } else { // 1. 终止后台数据接收任务避免任务残留导致资源泄漏 cts?.Cancel(); // 2. 关闭 TCP 客户端断开与服务器的连接释放网络资源 client?.Close(); // 3. 将 client 置为 null避免后续误操作已释放的对象 client null; // 4. 更新按钮状态为“启动”提示用户客户端已断开连接 button1.Text 启动; } } catch (Exception) { // 异常捕获抛出异常便于上层处理实际项目可替换为日志记录避免程序崩溃 throw; } }核心要点与易错点启动顺序先连接服务器再开启数据接收任务确保通信链路已建立避免接收任务报错资源释放停止客户端时必须按顺序终止任务→关闭客户端→重置对象避免资源泄漏和状态混乱异常处理当前代码直接抛出异常实际项目可优化为友好提示日志记录避免程序崩溃影响用户体验状态同步按钮文本与客户端连接状态保持同步便于用户直观判断当前通信状态3. 服务器连接方法connectServer/// summary /// 异步连接服务器更新按钮状态 /// /summary public async void ConnectToServer() { // 初始化 TCP 客户端 client new TcpClient(); // 异步连接服务器指定服务器 IP 与端口 await client.ConnectAsync(192.168.219.65, 9999); // 连接成功后更新按钮文本为“停止” button1.Text 停止; }核心要点与易错点服务器参数一致性连接的服务器 IP 与端口需与前文 TCP 服务器配置完全一致否则无法建立连接异步连接使用 ConnectAsync 实现异步连接避免阻塞主线程保证 UI 界面流畅响应连接状态校验实际项目可添加连接失败的异常处理给出友好提示提升用户体验4. 服务器响应帧接收方法AcceptData/// summary /// 后台接收服务器返回的响应帧解析并展示数据 /// 核心逻辑循环接收数据→提取有效数据→解析核心数据→转换为十六进制字符串→更新 UI 展示 /// /summary public void AcceptData() { // 初始化异步任务取消源控制后台接收任务的启停 cts new CancellationTokenSource(); // 启动后台异步任务持续接收服务器响应帧 Task.Run(async () { while (!cts.IsCancellationRequested) { // 校验客户端状态若客户端未初始化、未连接或无数据可接收跳过本次循环 if (client null || !client.Connected || client.Available 0) continue; // 获取客户端网络流用于读取服务器响应帧 NetworkStream stream client.GetStream(); // 定义临时缓冲区长度1024适配常见响应帧长度可根据需求调整 byte[] temp new byte[1024]; // 异步读取服务器响应帧count 为实际读取的有效字节数 int count await stream.ReadAsync(temp, 0, temp.Length); // 若读取字节数≤0说明服务器已断开连接退出循环 if (count 0) break; // 定义有效数据缓冲区长度为实际读取的字节数 byte[] realBuffer new byte[count]; // 将临时缓冲区中的有效数据拷贝至真实缓冲区去除冗余数据 Array.Copy(temp, realBuffer, count); // 简单校验若有效数据长度小于13字节Modbus 响应帧最小长度跳过本次数据 if (count 13) continue; // 解析 Modbus 响应帧核心数据第4、5字节高位在前 int data realBuffer[3] * 256 realBuffer[4]; // 控制台打印解析的数据便于调试 Console.WriteLine(data); // 跨线程更新 UI将有效数据转换为十六进制字符串追加展示 Invoke(new Action(() { string msg ByteToString(realBuffer); richTextBox1.Text 服务器返回的数据 msg Environment.NewLine; })); } }, cts.Token); // 传入取消令牌支持任务外部终止客户端停止时触发 }核心要点与易错点数据接收逻辑通过临时缓冲区接收数据再拷贝至有效缓冲区去除冗余数据保证数据解析准确帧校验通过数据长度校验≥13字节过滤无效数据避免解析异常适配 Modbus 协议数据解析按 Modbus 协议解析核心数据第4、5字节采用高位在前的计算方式确保解析结果正确异步接收使用 ReadAsync 实现异步接收避免阻塞主线程提升通信效率与 UI 流畅度跨线程 UI 更新必须使用 Invoke 方法否则会抛出“线程间操作无效”异常这是 Windows 窗体开发的核心规则5. 数据转换工具方法ByteToString/// summary /// 字节数组转十六进制字符串适配 UI 展示格式 /// 输入示例[01, 03, 00, 04] → 输出01 03 00 04 /// /summary /// param namedata字节数组/param /// returns转换后的十六进制字符串/returns public string ByteToString(byte[] data) { // 使用 BitConverter 转换为十六进制字符串替换分隔符为空格提升可读性 return BitConverter.ToString(data).Replace(-, ); }核心要点与易错点格式适配转换后的字符串格式与前文 TCP 服务器展示格式一致便于双向通信的日志对比可读性优化替换分隔符为空格使 UI 展示的字节数组更易阅读适配调试与查看需求6. 发送请求帧按钮事件button2_Click/// summary /// 向服务器发送请求帧按钮点击事件 /// 核心逻辑校验客户端状态→将输入文本转换为字节数组→通过网络流发送至服务器→更新 UI 展示 /// /summary private void button2_Click(object sender, EventArgs e) { // 校验客户端状态若客户端未初始化或未连接服务器直接返回避免无效发送 if (!client.Connected || client null) return; // 获取客户端网络流用于发送请求帧 NetworkStream stream client.GetStream(); // 将用户输入的文本转换为 UTF8字节数组与服务器编码保持一致避免乱码 byte[] bytes Encoding.UTF8.GetBytes(textBox1.Text); // 向服务器发送请求帧 stream.Write(bytes, 0, bytes.Length); // 跨线程更新 UI展示发送的请求帧内容 Invoke(new Action(() { richTextBox1.Text 客户端发送的请求帧: textBox1.Text Environment.NewLine; })); }核心要点与易错点状态校验发送前必须校验客户端是否已连接避免向未连接的客户端发送数据导致异常编码一致性使用 UTF8编码转换文本与前文 TCP 服务器接收端编码保持一致避免中文乱码数据发送通过网络流 Write 方法发送数据确保请求帧能准确传输至服务器UI 同步发送后及时更新 UI 展示便于用户确认请求帧已成功发送三、整体核心注意事项与优化建议1. 通信核心注意事项服务器参数一致性客户端连接的服务器 IP 与端口需与 TCP 服务器配置完全一致否则无法建立通信链路资源释放停止客户端时必须释放 TcpClient、CancellationTokenSource 等资源避免资源泄漏数据解析规范严格遵循 Modbus 协议解析响应帧确保数据解析准确避免数据错乱连接状态管理实时校验客户端连接状态避免在未连接状态下执行收发操作导致异常编码一致性收发数据的编码需与服务器保持一致本案例为 UTF8避免中文乱码2. 代码优化建议参数配置将服务器 IP、端口等配置提取到配置文件或界面输入框便于修改无需修改代码日志规范替换异常抛出为日志组件如 NLog记录通信日志、异常信息便于调试和线上问题排查UI 优化添加服务器参数输入界面、连接状态提示完善异常提示提升用户体验可添加清空日志功能资源清理添加窗体关闭事件在关闭时自动停止客户端、释放所有资源避免资源泄漏代码复用将数据转换、状态校验等通用逻辑封装为方法减少代码冗余提升可维护性异常处理细化异常类型针对连接失败、数据发送失败、数据解析失败等场景给出针对性提示便于用户排查问题3. 测试要点环境准备确保 TCP 服务器已启动客户端与服务器在同一局域网网络互通功能测试启动客户端连接服务器发送请求帧验证能否正常接收并解析服务器响应帧日志展示是否准确异常测试测试服务器未启动、网络断开、无效请求帧等场景验证程序异常处理能力兼容性测试与前文 TCP 服务器联动测试验证双向通信的稳定性与数据准确性
返回列表