C# WinForm TCP 服务器+WinForm TCP 客户端
2026/8/29 7:10:21 网站建设 项目流程

一、项目整体架构说明

1.1 项目核心功能

  • TCP 服务器初始化:自动获取本机 IPv4 地址,绑定指定端口,完成服务器基础配置

  • 多客户端并发处理:通过异步任务实现多客户端连接监听,支持同时处理多个客户端的消息接收

  • 实时消息展示:接收客户端消息后,跨线程更新 UI 控件,实现消息实时显示

  • 单/多客户端模式切换:提供单客户端与多客户端两种接收方法,适配不同使用场景

1.2 核心技术依赖

  • TCP 套接字(Socket):基于流模式(Stream)实现网络通信,采用 IPv4 地址族,遵循 TCP 协议

  • 异步任务(Task):避免 UI 卡顿,实现客户端并发监听与消息接收的非阻塞操作

  • CancellationTokenSource:异步任务取消源,用于终止监听与接收任务,实现资源优雅释放

  • DNS 解析:通过 Dns 类自动获取本机 IPv4 地址,无需手动配置 IP,提升灵活性

  • WinForm 控件:通过 RichTextBox 实时展示客户端消息,实现界面交互与状态反馈

1.3 核心变量与方法说明

  • Socket server:服务器端 Socket 对象,全局初始化,负责监听客户端连接请求,是整个服务器的核心对象

  • CancellationTokenSource cts/cts2:异步任务取消源,cts 用于终止客户端监听任务,cts2 用于终止单个客户端的数据接收任务,实现任务的可控终止

  • AcceptDataMul 方法:多客户端接收模式,通过两层异步任务实现多客户端并发连接与消息接收,是项目核心功能方法

  • AcceptDataSigle 方法:单客户端接收模式,仅处理单个客户端的连接与消息接收,适合测试或单客户端场景


二、核心代码逐行解析

2.1 命名空间引用

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms;

解析:引入网络通信(Socket、IPEndPoint、DNS)、异步任务(CancellationTokenSource、Task)、WinForm 控件等核心命名空间,为服务器初始化、客户端监听、消息接收及界面交互提供基础依赖,确保各类网络操作与界面更新可正常执行。

2.2 窗体类与构造函数

namespace _1服务端 { public partial class Form1 : Form { // 服务器 Socket 对象,全局初始化,用于监听客户端连接请求 Socket server = null; public Form1() { InitializeComponent(); } } }

解析:定义项目命名空间与窗体类,声明全局服务器 Socket 对象,构造函数仅完成窗体初始化,无额外业务逻辑,核心功能通过窗体加载事件实现,保证代码结构清晰。

2.3 窗体加载事件(Form1_Load):服务器初始化核心流程

private void Form1_Load(object sender, EventArgs e) { // 1. 实例化服务器 Socket 对象 // 参数1:AddressFamily.InterNetwork 指定使用 IPv4 地址族,InterNetworkV6 对应 IPv6 // 参数2:SocketType.Stream 指定数据传输采用流模式,是 TCP 协议的专属传输方式 // 参数3:ProtocolType.Tcp 指定通信协议为 TCP,实现可靠的面向连接的通信 server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 2. 绑定服务器 IP 与端口 string ipStr = ""; // 存储本机 IPv4 地址字符串 int port = 63323; // 端口号,范围0-65535,建议使用高位端口(1024以上),避免与系统预留端口冲突 // 获取本机主机名,通过 DNS 解析获取所有 IP 地址 // Dns.GetHostName():获取当前计算机的主机名称 // Dns.GetHostEntry():通过主机名解析对应的 IP 地址信息 IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); // 遍历 IP 地址列表,筛选出 IPv4 地址 foreach (IPAddress item in host.AddressList) { // 判断地址类型是否为 IPv4,避免获取到 IPv6 地址导致绑定失败 if (item.AddressFamily == AddressFamily.InterNetwork) { ipStr = item.ToString(); } } // 将字符串格式的 IP 转换为 IPAddress 对象,用于后续绑定 IPAddress address = IPAddress.Parse(ipStr); // 构建终端对象(包含 IP 与端口),是服务器绑定的核心对象 IPEndPoint endPoint = new IPEndPoint(address, port); server.Bind(endPoint); // 绑定 IP 与端口,完成服务器基础配置,绑定后服务器可监听该端口的请求 // 3. 开启服务器监听,参数100表示最大等待连接数,即最多可容纳100个客户端同时等待连接 server.Listen(100); // 4. 启动多客户端接收任务(也可替换为单客户端接收方法 AcceptDataSigle) // 多客户端模式:支持同时处理多个客户端连接与消息接收 AcceptDataMul(); }

解析:该方法是服务器初始化的核心,遵循“实例化 Socket→绑定 IP 端口→开启监听→启动接收任务”的标准流程,自动获取本机 IPv4 地址,无需手动配置,同时默认启动多客户端接收模式,适配多数场景需求,代码注释详细标注了每一步的作用与注意事项。

2.4 多客户端接收方法(AcceptDataMul)

// 异步任务取消源,用于终止客户端监听任务 CancellationTokenSource cts; // 异步任务取消源,用于终止单个客户端的数据接收任务 CancellationTokenSource cts2; public void AcceptDataMul() { // 初始化监听任务取消源,用于控制监听任务的终止 cts = new CancellationTokenSource(); // 启动异步任务,避免 UI 卡顿,循环监听客户端连接请求 Task.Run(() => { // 循环监听,直到任务被取消(cts.IsCancellationRequested 为 true) while (!cts.IsCancellationRequested) { // 接收客户端连接请求,返回客户端 Socket 对象 // Accept() 方法会阻塞线程,直到有客户端连接,因此必须放在异步任务中 Socket client = server.Accept(); if (client == null) { Console.WriteLine("客户端未连接"); break; } // 确认客户端正常连接,启动数据接收任务 if (client.Connected) { // 初始化当前客户端数据接收任务取消源,用于控制单个客户端接收任务的终止 cts2 = new CancellationTokenSource(); // 启动异步任务,循环接收当前客户端发送的数据 Task.Run(() => { while (!cts2.IsCancellationRequested) { try { // 初始化接收缓冲区,长度为客户端可用数据长度,避免缓冲区溢出 byte[] buffer = new byte[client.Available]; // 接收客户端数据,返回实际接收的字节数 // Receive() 方法会阻塞线程,直到接收到数据,因此放在异步任务中 int length = client.Receive(buffer); // 跨线程更新 UI,将接收的消息追加到 RichTextBox // 因为异步任务无法直接操作 UI 控件,需通过 Invoke 实现跨线程更新 Invoke(new Action(() => { richTextBox1.AppendText(Encoding.UTF8.GetString(buffer)); })); } catch (Exception) { // 接收异常,退出当前客户端接收循环,避免任务崩溃 break; } } }, cts2.Token); // 传入取消令牌,支持任务的可控终止 } } }, cts.Token); // 传入取消令牌,支持监听任务的可控终止 }

解析:该方法实现多客户端并发处理,核心逻辑为“循环监听客户端连接→为每个客户端启动独立接收任务→跨线程更新 UI”,通过两层异步任务实现客户端并发与数据实时接收,同时通过 CancellationTokenSource 实现任务的优雅终止,避免资源泄漏与线程阻塞,是项目的核心功能实现。

2.5 单客户端接收方法(AcceptDataSigle)

public void AcceptDataSigle() { // 初始化任务取消源,用于控制接收任务的终止 cts = new CancellationTokenSource(); // 启动异步任务,处理单个客户端的连接与数据接收 Task.Run(() => { // 接收单个客户端连接请求 Socket client = server.Accept(); // 循环接收客户端数据,直到任务被取消 while (!cts.IsCancellationRequested) { // 初始化接收缓冲区,长度为客户端可用数据长度 byte[] buffer = new byte[client.Available]; // 接收客户端数据 int length = client.Receive(buffer); // 跨线程更新 UI,将接收的消息追加到 RichTextBox Invoke(new Action(() => { richTextBox1.AppendText(Encoding.UTF8.GetString(buffer)); })); } }, cts.Token); }

解析:该方法仅支持单个客户端连接,逻辑相对简单,适合测试或单客户端场景,核心流程与多客户端模式一致,仅去掉了并发处理逻辑,仅处理单个客户端的消息接收,代码简洁易懂,可作为多客户端模式的基础参考。

2.6 核心步骤总结(代码注释提炼)

  1. 创建服务器 Socket 对象:new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),指定 IPv4、流模式、TCP 协议

  2. 绑定服务器终端:Bind(IPEndPoint),需指定本机 IPv4 地址与高位端口,完成服务器基础配置

  3. 开启服务器监听:Listen(最大等待连接数),设置可容纳的客户端等待数量

  4. 接收客户端连接请求:Accept(),返回客户端 Socket 对象,需放在异步任务中避免阻塞

  5. 接收客户端数据:Receive(),将接收的字节数组解码为字符串,通过 Invoke 跨线程更新 UI


三、核心易错点与注意事项

3.1 线程安全易错点

  • 异步任务中禁止直接操作 UI 控件,必须使用 Invoke 实现跨线程更新,否则会抛出线程安全异常,导致程序崩溃

  • 客户端接收任务需独立启动,避免阻塞主线程与其他客户端的接收操作,保证多客户端并发处理的流畅性

  • server.Accept() 与 client.Receive() 均为阻塞方法,必须放在异步任务中执行,否则会导致 UI 卡顿

3.2 资源释放易错点

  • 当前代码未实现服务器关闭与资源释放逻辑,需补充窗体关闭事件,调用 cts.Cancel() 终止异步任务,关闭 server 与 client 套接字,避免资源泄漏

  • 客户端接收异常时,需及时关闭客户端 Socket,避免无效连接占用系统资源,可在 catch 块中添加 client.Close() 逻辑

  • 多客户端模式下,每个客户端的接收任务需独立使用 CancellationTokenSource,避免任务终止相互影响,确保每个客户端的接收任务可独立控制

3.3 网络通信易错点

  • 端口号需避免使用低位端口(0-1023),此类端口多为系统预留,易导致绑定失败,建议使用1024以上的高位端口

  • IP 地址筛选需确认 AddressFamily 为 InterNetwork(IPv4),避免获取到 IPv6 地址导致绑定失败,可通过断点调试确认 ipStr 的值

  • 接收数据时需判断接收长度,避免处理空数据,同时需统一编码格式(本项目使用 UTF8),防止中文消息乱码,与客户端编码保持一致

  • 服务器绑定的端口需确保未被其他程序占用,否则会抛出绑定异常,可通过命令行(netstat -ano)查看端口占用情况

3.4 其他注意事项

  • 可在接收数据时添加客户端标识(如 IP+端口),区分不同客户端的消息,便于界面展示,提升用户体验

  • 当前代码中 cts2 为全局变量,会导致多客户端接收任务的取消源相互覆盖,需改为局部变量,每个客户端的接收任务独立使用自己的取消源

  • 可优化服务器初始化逻辑,将 IP、端口改为可配置输入框,避免硬编码,提升程序的灵活性与可扩展性

WinForm TCP 客户端

一、项目整体架构说明

1.1 项目核心功能

  • TCP 客户端初始化:创建客户端 Socket,异步连接指定服务器

  • 消息发送功能:向服务器发送文本消息,支持发送状态提示

  • 异常处理与资源释放:连接/发送失败时,自动关闭客户端并释放资源

  • 界面状态联动:连接成功后切换按钮状态,避免重复连接或无效发送

1.2 核心技术依赖

  • TCP 套接字(Socket):基于流模式(Stream)实现网络通信,采用 IPv4 地址族

  • 异步编程(async/await):实现非阻塞连接,避免 UI 卡顿

  • WinForm 控件:通过按钮、文本框、标签实现界面交互与状态展示

  • 编码处理:统一使用 UTF8 编码,避免中文消息乱码

1.3 核心变量与方法说明

  • Socket client:客户端 Socket 对象,负责与服务器建立连接、发送数据

  • button1_Click 方法:连接服务器按钮事件,实现异步连接与状态切换

  • button2_Click 方法:发送消息按钮事件,实现数据发送、异常处理与资源释放


二、核心代码逐行解析

2.1 命名空间引用

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;

解析:引入网络通信(Socket、IPEndPoint)、异步任务(Task)、WinForm 控件等核心命名空间,为客户端连接、消息发送及界面交互提供基础依赖,确保各类网络操作可正常执行。

2.2 窗体类与构造函数

namespace _2客户端 { public partial class Form1 : Form { // 客户端 Socket 对象,全局初始化,用于与服务器通信 Socket client; public Form1() { InitializeComponent(); } } }

解析:定义项目命名空间与窗体类,声明全局客户端 Socket 对象,构造函数仅完成窗体初始化,无额外业务逻辑,核心功能通过按钮点击事件实现。

2.3 连接服务器按钮事件(button1_Click)

private async void button1_Click(object sender, EventArgs e) { // 开始连接,捕获异常保证程序稳定性 try { // 1. 创建客户端 Socket 实例 // 参数1:AddressFamily.InterNetwork 指定使用 IPv4 地址族 // 参数2:SocketType.Stream 指定数据传输采用流模式(TCP 专属) // 参数3:ProtocolType.Tcp 指定通信协议为 TCP client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 2. 创建服务器终端对象(IP+端口),需与服务器配置一致 IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.219.12"), 63323); // 3. 异步连接服务器,避免 UI 卡顿,await 等待连接结果 // 同步连接方式:client.Connect(endpoint); 会阻塞线程 await client.ConnectAsync(endpoint); // 4. 连接成功,更新界面状态 label1.Text = "连接成功"; button1.Enabled = false; // 禁用连接按钮,避免重复连接 button2.Enabled = true; // 启用发送按钮,允许发送消息 } catch (Exception) { // 连接失败,提示用户并返回 MessageBox.Show("服务器未打开"); return; } }

解析:核心实现客户端异步连接服务器,流程为“实例化客户端 Socket→创建服务器终端→异步连接→更新界面状态”,采用 async/await 实现非阻塞连接,同时通过异常捕获处理连接失败场景,保证程序稳定性。

2.4 发送消息按钮事件(button2_Click)

private void button2_Click(object sender, EventArgs e) { // 1. 校验客户端状态:未初始化或未连接时,提示用户并返回 if (client == null || !client.Connected) { MessageBox.Show("还没连接到服务器,请先连接服务器"); return; } // 2. 校验发送内容:为空时提示用户并返回 if (string.IsNullOrEmpty(textBox1.Text)) { MessageBox.Show("发送数据不能为空"); return; } // 3. 发送数据,捕获异常处理发送失败场景 try { // 将文本内容转换为 UTF8 编码的字节数组 byte[] data = Encoding.UTF8.GetBytes(textBox1.Text); // 向服务器发送数据 client.Send(data); // 更新状态提示 label1.Text = "发送成功"; } catch (Exception) { // 发送失败,更新状态提示 label1.Text = "发送失败"; // 4. 资源释放:发送失败时,关闭客户端连接并释放资源 if (client != null) { // 若客户端仍处于连接状态,先关闭连接 if (client.Connected) client.Shutdown(SocketShutdown.Both); // 关闭客户端 Socket client.Close(); // 释放客户端资源 client.Dispose(); } // 5. 恢复界面状态,允许重新连接 button1.Enabled = true; button2.Enabled = false; } }

解析:实现消息发送功能,核心逻辑为“校验状态→编码数据→发送消息→异常处理→资源释放”,发送前严格校验客户端状态与消息内容,发送失败时自动关闭客户端并释放资源,同时恢复界面状态,便于用户重新连接。

2.5 核心步骤总结

  1. 创建客户端 Socket 对象:new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

  2. 创建服务器终端:IPEndPoint(服务器 IP, 端口),需与服务器配置一致

  3. 异步连接服务器:await client.ConnectAsync(endpoint),避免 UI 卡顿

  4. 校验发送条件:客户端已连接、消息内容非空

  5. 发送数据:client.Send(字节数组),统一使用 UTF8 编码

  6. 异常处理与资源释放:发送失败时,关闭客户端并释放资源,恢复界面状态


三、核心易错点与注意事项

3.1 连接相关易错点

  • 服务器 IP 与端口必须与服务器端配置完全一致,否则无法建立连接

  • 连接操作需使用异步方式(await ConnectAsync),同步连接会阻塞 UI 线程,导致界面卡顿

  • 连接成功后需及时禁用连接按钮,避免重复创建客户端连接,导致资源浪费

3.2 发送消息相关易错点

  • 发送前必须校验客户端状态(client != null && client.Connected),避免向未连接的客户端发送消息,引发异常

  • 消息编码需统一使用 UTF8,避免中文消息乱码,与服务器端编码保持一致

  • 发送数据时需判断消息内容非空,避免发送空数据,浪费网络资源

3.3 资源释放易错点

  • 发送失败时,必须通过 Shutdown、Close、Dispose 三步释放客户端资源,避免资源泄漏

  • Shutdown 需传入 SocketShutdown.Both,同时关闭发送与接收通道,确保连接彻底断开

  • 资源释放后需恢复界面按钮状态,允许用户重新连接服务器

3.4 其他注意事项

  • 客户端 Socket 为全局变量,避免重复实例化,仅在发送失败或重新连接时重新创建

  • 可优化界面设计,将服务器 IP、端口改为可配置输入框,避免硬编码,提升灵活性

  • 可添加消息接收功能,实现客户端与服务器的双向通信,完善聊天室功能

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询