公司动态

C# WinForms TCP Socket 服务端

📅 2026/8/5 8:28:57
C# WinForms TCP Socket 服务端
一、Socket 基础概念1. 什么是 Socket套接字Socket 是网络通信的通信端点可以理解为程序进行网络数据收发的 “接口 / 电话机”。 两台程序想要通过网络通信两端都必须创建 Socket。IP 地址定位网络中的电脑住址端口号定位电脑上运行的具体程序房间号Socket程序收发网络数据的载体2. TCP Socket 创建参数解析new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)AddressFamily.InterNetwork使用 IPv4 地址协议SocketType.Stream数据流模式面向连接对应 TCPProtocolType.Tcp指定通信协议为 TCPTCP 特点先建立连接、可靠传输、不会丢包、有序适合设备通信、上位机、聊天程序。3. TCP 通信角色区分服务端 Socket (server)固定 IP 端口被动等待客户端连接客户端 Socket (client)主动发起连接连接服务端 IP 端口重点server 套接字只负责接收连接每接入一个客户端会生成独立 client 套接字单独通信。二、TCP 服务端标准开发五大步骤代码主线实例化 Socket 对象new Socket()绑定 Bind将 Socket 绑定本机 IP 端口IPEndPoint开启监听 Listen开始等待客户端发起连接接受连接 Accept ()阻塞等待客户端接入生成客户端 Socket循环接收数据 Receive ()持续读取客户端发送的字节数据三、核心类详解Dns域名解析类用来获取本机主机名、解析 IP 地址IPHostEntry主机信息实体包含本机所有 IP 地址列表IPAddress封装单个 IP 地址IPEndPoint IPAddress 端口号代表一个完整网络终端CancellationTokenSource线程令牌安全控制循环线程停止Encoding.UTF8字节数组与字符串互相转换网络传输只有 byte []四、本机 IPv4 自动获取逻辑解析IPHostEntry iPHost Dns.GetHostEntry(Dns.GetHostName()); foreach (IPAddress item in iPHost.AddressList) { if (item.AddressFamily AddressFamily.InterNetwork) { ipStr item.ToString(); } }逻辑说明Dns.GetHostName()获取电脑本机名称Dns.GetHostEntry()根据主机名拿到本机所有 IP遍历地址列表筛选InterNetwork类型只保留 IPv4 地址作用自动适配电脑 IP不用手动硬编码 IP 地址。五、端口说明int port 63323;端口范围0 ~ 655350~1023系统保留端口尽量不要使用推荐使用1024 ~ 65535 之间端口绑定代码IPAddress address IPAddress.Parse(ipStr); IPEndPoint endPoint new IPEndPoint(address, port); server.Bind(endPoint);监听开启server.Listen(100);Listen 参数最大等待连接队列长度。六、两种服务端模式对比模式 1AcceptDataSigle () 单客户端版本功能仅支持同时连接一个客户端运行逻辑开启 Task 异步线程执行server.Accept()阻塞等待客户端连接成功接入客户端 Socket 后进入 while 循环持续调用 Receive 读取数据重大缺陷新客户端发起连接时无法同时接入只能服务一个客户端工业通信、上位机项目不适用。模式 2AcceptDataMul () 多客户端版本【课程推荐方案】采用双层嵌套线程模型支持多个客户端同时连接外层线程while 循环不断执行server.Accept()持续监听、接收新客户端连接每成功连接一个客户端立刻创建独立线程处理收发。内层线程每个客户端独立线程为每一个客户端 Socket 单独开启任务循环接收该客户端下发的数据。核心思想一个客户端一条接收线程客户端之间互不干扰。七、数据接收相关知识点1. Receive () 接收数据byte[] buffer new byte[client.Available]; int length client.Receive(buffer);client.Available当前接收缓冲区中已经到达的字节数量Receive(buffer)将网络数据读取到字节数组 buffer返回实际收到字节长度⚠️ 网络传输底层只有字节数组字符串必须转 byte [] 发送收到 byte [] 再转回字符串展示。Encoding.UTF8.GetString(buffer); //字节数组 → 字符串2. WinForms 跨线程 UI 操作重中之重规则子线程不能直接操作窗体控件richTextBox、TextBox 等直接调用会报错跨线程操作无效。 解决方案使用Invoke()切换至 UI 主线程更新控件Invoke(new Action(() { richTextBox1.AppendText(Encoding.UTF8.GetString(buffer)); }));八、线程控制CancellationTokenSource创建令牌对象CancellationTokenSource cts new CancellationTokenSource();cts.Token传入 Task用于线程内部判断退出条件!cts.IsCancellationRequested循环条件判断是否请求终止线程调用cts.Cancel()即可触发信号结束 while 循环 作用优雅关闭线程避免暴力终止造成资源异常。代码结构外层监听线程使用 cts每个独立客户端接收线程单独创建 cts2。九、当前代码存在的缺陷与隐患考点重点记录buffer 数组分配方式错误new byte[client.Available]存在分包风险。TCP 是流式传输数据可能分多次到达Available 只代表当下缓冲区数据容易出现接收不全、丢数据。server.Accept()阻塞无法被令牌取消 Accept () 属于阻塞方法在等待客户端连接时就算触发 CancellationToken线程也不会立刻退出。没有处理客户端断开连接 客户端正常下线时Receive () 返回 0代码未判断 length0不会主动释放 Socket会持续进入异常循环。缺少 Socket 资源释放 客户端断开后没有执行client.Close()、client.Dispose()长期运行会内存泄漏、端口占用。异常处理简单粗暴 catch 只执行 break没有区分异常类型网络断开、程序报错、强制关闭等不方便调试排查。多客户端令牌对象未统一管理 每个客户端新建 cts2客户端大量接入时会创建大量令牌对象缺少统一回收机制。十、核心方法汇总表表格方法功能说明Socket.Bind(IPEndPoint)将套接字绑定本机 IP 与端口Socket.Listen(int)开启监听准备接收客户端连接Socket.Accept()阻塞等待客户端连接返回客户端 SocketSocket.Receive(byte[])接收客户端发送的字节数据Control.Invoke(Action)子线程安全更新窗体控件Dns.GetHostName()获取本机计算机名称Dns.GetHostEntry(hostName)通过主机名获取本机 IP 信息十一、完整程序运行流程窗体加载事件 Form1_Load 启动创建服务端 Socket自动获取本机 IPv4 地址组装 IPEndPointBind 绑定 IP 端口Listen 开启监听调用 AcceptDataMul () 启动多客户端监听线程线程阻塞等待客户端连接客户端连接成功 → 分配独立接收线程线程循环调用 Receive 接收字节数据通过 Invoke 切换 UI 线程将字节转为字符串显示到富文本框出现网络异常时跳出循环终止当前客户端接收任务十二、拓展补充Socket 分类TCPStream 流式套接字本次代码 UDPDatagram 数据报套接字无连接、不需要 Accept、速度快可能丢包。WebSocket 和 Socket 区别Socket 是底层网络通信接口WebSocket 是浏览器专用、基于 HTTP 升级后的长连接本质依旧依托 Socket 实现。上位机通信常用场景 Modbus TCP、传感器数据采集、PLC 通信、设备监控底层全部使用 TCP Socket 开发。namespace _1.服务端 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } Socket server null; private void Form1_Load(object sender, EventArgs e) { //1.实例化服务器对象 //参数1 地址类型 InterNetwork属于ipv4类型 InterNetworkV6属于ipv6类型 //参数2 SocketType.Stream 指定数据传输的时候使用数据流的方式进行传输 //参数3 指定通信协议 ProtocolType.Tcp 采用的tcp通信 server new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); //把服务器对象绑定给一个ip和端口号 //ip地址字符串 string ipStr ; //端口号 建议不要写太小 范围0-65535 int port 63323; //获取当前电脑的ip信息 //Dns.GetHostName()获取计算主机名称 //Dns.GetHostEntry() 通过主机名解析成对应的ip IPHostEntry iPHost Dns.GetHostEntry(Dns.GetHostName()); //iPHost.AddressList地址列表 foreach (IPAddress item in iPHost.AddressList) { if (item.AddressFamily AddressFamily.InterNetwork)//查询判断是不是ipv4的地址 { ipStr item.ToString(); } } //地址类型 IPAddress address IPAddress.Parse(ipStr);//把字符串转成地址类型 //终端对象包含ip和端口 IPEndPoint endPoint new IPEndPoint(address, port); server.Bind(endPoint);//绑定终端 //3.开启服务器 server.Listen(100);//容纳客户端数量 //使用哪些技术 //服务器可以接收多个客户端使用线程 //客户端需要不停的发消息需要while(true) for 一直处于接收状态 //多个客户端需要使用线程每个客户端需要发消息又得使用线程需要两层嵌套 //4.接收客户端发来的请求 //AcceptDataSigle();//接收单个客户端的方法 AcceptDataMul();//接收多个客户端 } CancellationTokenSource cts; CancellationTokenSource cts2; public void AcceptDataMul() { //接收客户端需要写在线程 cts new CancellationTokenSource(); Task.Run(() { while (!cts.IsCancellationRequested) { //接收多个客户端 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]; int length client.Receive(buffer); Invoke(new Action(() { richTextBox1.AppendText(Encoding.UTF8.GetString(buffer)); })); } catch(Exception) { break; } } },cts2.Token); } } },cts.Token); } public void AcceptDataSigle() { cts new CancellationTokenSource(); Task.Run(() { //server 服务器 //client 客户端 Socket client server.Accept();//接收客户端 //处理客户端发来的数据 while (!cts.IsCancellationRequested) { //定义字节数组 数组长度为读取的可用数据的长度 byte[] buffer new byte[client.Available]; //Receive()接收客户端的数据 int length client.Receive(buffer); Invoke(new Action(() { richTextBox1.AppendText(Encoding.UTF8.GetString(buffer)); })); } },cts.Token); } //1.创建服务器对象 new socket() //2.服务器对象绑定终端 Bind(IPEndPoint) //3.服务器开启监听 .listen //4.接收客户端连接请求 .accept() //5.接受发来的数据 .receive() } }十三、OSI七层网络模型1. 应用层面向应用程序给软件提供网络服务 协议HTTP、HTTPS、FTP、DNS、SMTP 数据单元数据2. 表示层数据编码、加密解密、压缩解压 作用统一数据格式不同系统能看懂数据 例图片 jpg、文本编码、SSL 加密旧划分3. 会话层建立、维持、断开两台应用之间通信会话 负责会话同步、断点恢复小总结应用、表示、会话三层 → TCP/IP 统一合并为【应用层】4. 传输层重点TCP/UDP 在这里端到端通信两个程序之间传输数据 协议TCP可靠、面向连接、有握手、重传文件传输、网页UDP不可靠、无连接、速度快直播、语音、游戏 设备防火墙 数据单元段 (Segment)5. 网络层寻址、路由选择跨网段传输 协议IP、ICMP、ARP (有争议)设备路由器数据单元包 (Packet)6. 数据链路层同一局域网内传输MAC 地址寻址 协议以太网协议 设备交换机、网卡数据单元帧 (Frame)7. 物理层传输电信号 / 光信号、比特流 网线、光纤、集线器、电压电平 数据单元比特 (bit) 0 和 1