C# TCP 客户端开发笔记(TcpClient)
一、整体功能概述
该代码基于 C# Windows Forms 框架,实现了一个 TCP 客户端程序,用于与 TCP 服务端进行通信,核心功能包括:
连接 / 断开 TCP 服务端
向服务端发送文本数据
接收服务端返回的数据并在界面显示
维护连接状态并提供用户交互反馈
二、核心技术点与类库依赖
1. 关键命名空间
System.Net
:提供 IP 地址(IPAddress
)和网络端点(IPEndPoint
)支持System.Net.Sockets
:提供 TCP 客户端核心类(TcpClient
、NetworkStream
)System.Threading.Tasks
:支持异步操作,避免 UI 线程阻塞System.Windows.Forms
:提供 Windows 图形界面组件System.Text
:提供字符串与字节数组的编码转换
2. 核心组件说明
TcpClient
:TCP 客户端核心类,负责与服务端建立连接和管理通信IPEndPoint
:表示网络端点(IP 地址 + 端口),用于标识客户端和服务端NetworkStream
:基于TcpClient
的数据流,用于实际的数据传输CancellationTokenSource
:用于取消异步任务,特别是在断开连接时Invoke(Action)
:确保在 UI 线程更新界面控件,避免跨线程操作异常
三、代码结构拆解
1. 全局变量定义
// TCP客户端对象 TcpClient tcpClient = null; // 服务端网络端点(IP+端口) IPEndPoint remoteEP = null; // 任务取消令牌源 CancellationTokenSource cts = null;
2. 构造函数
public Form1() {InitializeComponent(); // 初始化Windows Forms控件 }
说明:默认构造函数,仅负责初始化界面控件
3. 核心功能方法详解
(1)连接 / 断开按钮点击事件
private async void button1_Click(object sender, EventArgs e) {try{// 根据按钮文本判断执行连接或断开操作if (button1.Text == "连接"){await ConnectServer(); // 连接服务器AcceptResponse(); // 开始接收服务器响应}else{DisConnectServer(); // 断开连接}}catch (Exception){throw;} }
逻辑:通过按钮文本状态切换连接状态,使用
async/await
处理异步操作
(2)连接服务器(ConnectServer
)
private async Task ConnectServer() {// 创建本地端点(任意本地IP,系统自动分配端口)IPEndPoint LocalEP = new IPEndPoint(IPAddress.Any, 0);// 定义服务端端点(IP和端口)remoteEP = new IPEndPoint(IPAddress.Parse("172.16.0.28"), 9999);// 初始化TcpClient并绑定本地端点tcpClient = new TcpClient(LocalEP);// 异步连接到服务端await tcpClient.ConnectAsync(IPAddress.Parse("172.16.0.28"), 9999);// 更新按钮文本为"中断",表示已连接button1.Text = "中断"; }
关键点:
IPAddress.Any
:表示使用本地任意可用 IP 地址端口 0:表示让系统自动分配可用端口
ConnectAsync
:异步连接方法,不会阻塞 UI 线程服务端 IP 和端口硬编码,实际应用中应改为可配置
(3)断开连接(DisConnectServer
)
private void DisConnectServer() {// 取消接收响应的任务cts?.Cancel();// 关闭TCP客户端连接tcpClient?.Close();// 更新按钮文本为"连接",表示已断开button1.Text = "连接"; }
资源释放逻辑:先取消任务,再关闭连接,确保资源正确释放
(4)接收服务器响应(AcceptResponse
)
private void AcceptResponse() {// 初始化取消令牌源cts = new CancellationTokenSource();// 启动异步任务接收数据Task.Run(async () =>{while (!cts.IsCancellationRequested){try{// 检查客户端是否连接且有可用数据if (!tcpClient.Connected || tcpClient.Available == 0) continue;// 获取网络流NetworkStream stream = tcpClient.GetStream();// 创建缓冲区(大小为可用数据量)byte[] buffer = new byte[tcpClient.Available];// 异步读取数据int count = await stream.ReadAsync(buffer, 0, buffer.Length);if (count == 0) continue;// 线程安全地更新UIInvoke(new Action(() =>{string data = Encoding.UTF8.GetString(buffer);richTextBox1.Text += $"{tcpClient.Client.RemoteEndPoint},{data}" + Environment.NewLine;}));}catch (Exception){throw;}}}, cts.Token); }
核心逻辑:
使用
Task.Run
在后台线程接收数据,避免阻塞 UItcpClient.Available
:获取可读取的数据长度ReadAsync
:异步读取数据,非阻塞操作Invoke
:确保在 UI 线程更新richTextBox1
控件
(5)发送数据按钮点击事件(button2_Click
)
private void button2_Click(object sender, EventArgs e) {// 检查客户端是否已连接if (tcpClient != null && tcpClient.Connected){// 获取网络流NetworkStream stream = tcpClient.GetStream();// 获取输入框文本并转换为字节数组string msg = textBox1.Text;byte[] buffer = Encoding.UTF8.GetBytes(msg);// 发送数据stream.Write(buffer, 0, buffer.Length);// 在界面显示已发送的数据richTextBox1.Text = $"我是{tcpClient.Client.LocalEndPoint}{msg}" + Environment.NewLine;}else{// 未连接时提示用户MessageBox.Show("先连接服务器,再发送");return;} }
发送流程:
检查连接状态
获取输入文本
转换为字节数组(UTF8 编码)
通过网络流发送
在界面显示发送记录
四、界面控件与交互逻辑
button1
:连接 / 断开按钮,文本状态表示当前连接状态button2
:发送按钮,点击时发送textBox1
中的内容textBox1
:输入框,用于输入要发送的文本richTextBox1
:显示区域,展示发送和接收的消息
五、潜在问题与优化建议
1. 现有代码问题
硬编码服务端地址:服务端 IP 和端口硬编码在代码中,不便于修改
异常处理不完善:多数异常仅抛出未做处理,可能导致程序崩溃
无连接状态实时检测:服务端异常断开时,客户端不能及时感知
发送数据未使用异步:
stream.Write
是同步方法,大数据量时可能卡顿 UI接收缓冲区设计:依赖
tcpClient.Available
创建缓冲区,不适合处理大数据
2. 优化建议
将服务端地址改为可配置:添加两个输入框让用户输入 IP 和端口
完善异常处理:
try {await tcpClient.ConnectAsync(ip, port); } catch (SocketException ex) {MessageBox.Show($"连接失败: {ex.Message}");return; }
添加连接心跳检测:定期发送心跳包检测连接状态
使用异步发送数据:
await stream.WriteAsync(buffer, 0, buffer.Length);
使用固定大小缓冲区:
byte[] buffer = new byte[1024]; // 固定大小缓冲区 int bytesRead; while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0) {// 处理读取的数据 }
添加 Form 关闭时的资源释放:
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {DisConnectServer(); }
六、使用与测试说明
确保服务端已启动并监听指定 IP 和端口
客户端点击 "连接" 按钮建立连接
在输入框中输入文本,点击 "发送" 按钮发送数据
接收的服务端响应会显示在下方文本区域
点击 "中断" 按钮断开与服务端的连接
该客户端与之前的服务端代码配合使用,可以实现基本的 TCP 通信功能,适合作为 C# 网络编程的入门示例。