C# WinForms TCP Socket 客户端

📅 2026/8/4 5:08:24
C# WinForms TCP Socket 客户端
一、客户端核心思路TCP 通信分为服务端与客户端服务端Bind 绑定端口 → Listen 监听 → Accept 等待连接被动客户端主动发起连接不需要 Bind、不需要 Listen、不需要 Accept。 客户端 Socket 只做两件事连接服务端 收发数据。二、代码整体结构说明窗体控件button1连接服务器按钮button2发送数据按钮textBox1输入待发送文本label1状态提示文本 全局变量Socket client;客户端套接字对象三、连接服务器button1_Click核心代码解析private async void button1_Click(object sender, EventArgs e) { try { //1. 创建TCP客户端Socket client new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //2. 构造服务端终端服务端IP 端口 IPEndPoint endPoint new IPEndPoint(IPAddress.Parse(192.168.219.30), 63323); //3. 异步连接服务端 await client.ConnectAsync(endPoint); label1.Text 连接成功; button1.Enabled false; button2.Enabled true; } catch (Exception) { MessageBox.Show(服务器未打开); return; } }关键知识点Socket 构造参数和服务端完全一致AddressFamily.InterNetwork(IPv4)、SocketType.Stream、ProtocolType.TcpIPEndPoint填写服务端的 IP 地址与端口必须和服务端 Bind 的端口一致⚠️ IP 地址需要修改为服务端电脑实际 IP端口号必须一致63323两种连接方式对比client.Connect(endPoint)同步连接阻塞 UI 线程界面会卡死await client.ConnectAsync(endPoint)异步连接搭配 async void不卡住窗体推荐写法连接成功后控件状态切换 禁用【连接按钮】启用【发送按钮】防止重复连接。异常捕获无法连接时弹出提示常见原因服务端程序没有启动IP / 端口填写错误防火墙拦截两台电脑不在同一局域网四、发送数据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; } try { //字符串 → UTF8字节数组 byte[] data Encoding.UTF8.GetBytes(textBox1.Text); client.Send(data); label1.Text 发送成功; } catch (Exception) { label1.Text 发送失败; //连接断开释放资源 if (client ! null) { if (client.Connected) client.Shutdown(SocketShutdown.Both); client.Close(); client.Dispose(); } button1.Enabled true; button2.Enabled false; } }关键知识点网络只能传输字节数组 byte []发送流程字符串 →Encoding.UTF8.GetBytes()→ byte [] 服务端接收后反向转换byte [] →Encoding.UTF8.GetString()→ 字符串client.Send(byte[])向服务端发送字节数据前置校验非常重要防止未建立连接就调用 Send直接报错崩溃禁止发送空数据发送失败资源回收逻辑当发送异常网络断开、服务端下线client.Shutdown(SocketShutdown.Both); //关闭读写通道 client.Close(); //关闭套接字 client.Dispose(); //释放内存资源SocketShutdown.Both同时禁止读取和写入。 回收完成后恢复按钮状态允许用户重新连接。五、客户端与服务端代码差异对比表格功能TCP 服务端TCP 客户端Bind 绑定✅ 需要绑定本机 IP 端口❌ 不需要 BindListen 监听✅ 需要❌ 不需要Accept 接收连接✅ 需要循环等待客户端❌ 不需要Connect 连接❌ 不需要✅ 主动 Connect/ConnectAsyncSocket 作用server 套接字专门等待连接通信交给 client 套接字唯一 client 套接字同时负责收发六、当前代码存在的缺陷重点记录⚠️缺少接收服务端消息的逻辑当前客户端只能发送不能接收服务端下发的数据。需要新增循环 Receive 线程监听服务端推送消息。IP 地址硬编码代码里直接写死192.168.219.30优化方案使用文本框让用户手动输入服务端 IP。异常处理笼统只捕获全部 Exception无法区分连接超时、端口不可达、网络中断等不同错误调试不方便。没有心跳检测无法实时感知连接是否意外断开比如网线拔掉只有发送数据时才会触发异常。连接成功后重复点击连接按钮没有拦截依靠按钮 Enabled 控制若代码异常导致按钮状态错乱可以重复创建 Socket造成资源泄漏。发送没有异步版本client.Send()是同步方法大数据发送时可能短暂卡顿界面高级写法使用SendAsync。七、核心方法速查表表格方法作用Socket.ConnectAsync(IPEndPoint)异步主动连接服务端推荐Socket.Connect(IPEndPoint)同步连接阻塞界面Socket.Send(byte[])发送字节数据到远端Socket.Shutdown(SocketShutdown.Both)关闭套接字读写通道Socket.Close()关闭套接字Socket.Dispose()释放套接字占用系统资源client.Connected判断套接字当前是否处于连接状态八、完整通信联调流程服务端 客户端启动【服务端程序】服务端完成 Bind、Listen开启监听启动【客户端程序】点击【连接服务器】客户端 ConnectAsync 成功提示 “连接成功”客户端文本框输入内容点击发送服务端接收字节数据转换成字符串展示在富文本框九、拓展补充局域网通信注意事项两台电脑连接同一个 WiFi / 局域网关闭系统防火墙或者放行程序使用ipconfig查询服务端本机 IPv4 地址同步与异步选择 WinForms 窗体项目网络操作优先使用Async异步方法避免 UI 界面卡死。完整通信模型 标准双向通信 服务端接收客户端消息 向客户端发送消息 客户端发送消息 循环接收服务端消息当前代码缺失这部分public partial class Form1 : Form { public Form1() { InitializeComponent(); } Socket client; //开始链结 private async void button1_Click(object sender, EventArgs e) { try { //1.创建客户端实例 client new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //2.创建终端 IPEndPoint endPoint new IPEndPoint(IPAddress.Parse(192.168.219.30),63323); //3.开始连接服务器 //client.Connect(endPoint);//同步链接 await client.ConnectAsync(endPoint);//等待异步连接结果 label1.Text 连接成功; button1.Enabled false; button2.Enabled true; } catch(Exception) { MessageBox.Show(服务器未打开); return; } } //发送 private void button2_Click(object sender, EventArgs e) { if (client null || !client.Connected) { MessageBox.Show(还没连接到服务器请先连接服务器); return; } if (string.IsNullOrEmpty(textBox1.Text)) { MessageBox.Show(发送数据不能为空); return; } //发送数据 try { byte[] data Encoding.UTF8.GetBytes(textBox1.Text); client.Send(data);//发送数据 label1.Text 发送成功; } catch (Exception) { label1.Text 发送失败; if (client ! null) //客户端不等于空 { if (client.Connected) client.Shutdown(SocketShutdown.Both);//客户端还处于连接状态 关闭连接 client.Close();//关闭客户端 client.Dispose();//释放资源 } button1.Enabled true; button2.Enabled false; } } }