尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

C# 语言进阶(十)TCP网络

C# 语言进阶(十)TCP网络
📅 发布时间:2026/7/7 4:16:30

本篇核心知识点:TCP 三次握手完整流程、TCP 四次挥手完整流程、阻塞 IO 缺陷、多线程解决阻塞、网络通用 DLL 库封装、服务端 / 客户端 Socket 分层封装、项目复用方案、网络异常崩溃处理、面试高频网络考点

一、TCP 三次握手(连接建立)

1. 核心概念

TCP 是面向连接可靠协议,客户端调用Connect()、服务端调用Accept()底层自动完成三次握手,对上层代码透明,无需手动发送同步包;作用确认双方收发能力,防止失效连接请求占用服务端资源。

2. 关键标识释义

SY:同步标志,发起连接请求

ACK:确认标志,回复对方收到数据

3. 分步完整流程

  1. 第一次握手(客户端→服务端)

    客户端调用 Connect,发送 SY 同步报文,客户端状态变为SY_SENT,向服务端发起连接申请。

  2. 第二次握手(服务端→客户端)

    服务端处于 Listen 监听状态,收到 SY 报文,回复SY+ACK报文,同步自身连接意愿并确认收到客户端请求,服务端进入SY_RCVD状态。

  3. 第三次握手(客户端→服务端)

    客户端收到服务端双标志报文,单独回复 ACK 确认报文,双方切换至ESTABLISHED稳定传输状态,握手完成,可正常收发数据。

4. 工程对应代码触发点

客户端Socket.Connect()内部封装完整三次握手;

服务端Socket.Accept()阻塞等待握手完成后,才返回客户端套接字。

5. 拓展:为什么需要三次握手

防止历史失效连接报文延迟到达服务端,建立无效连接占用端口;双向验证发送、接收通道正常,保障后续数据可靠传输。

二、TCP 四次挥手(连接断开)

1. 核心概念

TCP 全双工通道,收发通道独立,关闭时双方需分别告知对方不再发送数据,共四次报文交互;调用Socket.Close()底层自动触发挥手流程。

2. 分步完整流程

  1. 第一次挥手(主动关闭方)

    客户端 / 服务端调用 Close,发送 FIN 终止报文,进入FIN_WAIT_1状态,表示本方不再发送新数据,但仍能接收对方剩余消息。

  2. 第二次挥手(被动方回复 ACK)

    被动端收到 FIN,回复 ACK 确认报文,进入CLOSE_WAIT,此时被动端可继续发送未传输完毕数据。

  3. 第三次挥手(被动方发 FIN)

    被动端所有数据发送完毕,发送 FIN 报文告知对方无数据再发送。

  4. 第四次挥手(主动方 ACK 确认)

    主动端收到 FIN,回复 ACK,等待一段时间无报文后彻底释放套接字资源,连接完全关闭。

3. 代码层面问题

直接关闭客户端进程会强制断开,跳过完整挥手流程,服务端 Receive 读取数据返回 0,未做判断会直接抛出异常导致程序崩溃。

4. 拓展:四次挥手必要性

全双工读写分离,一方发完数据不代表另一方数据传输完毕,必须分两次告知终止发送,保证缓冲区残留数据全部接收。

三、阻塞 IO 致命缺陷(基础单线程网络问题)

1. 阻塞方法清单

Accept()、Receive()均为阻塞方法,线程执行时暂停,直到有客户端连接 / 收到数据才恢复运行。

2. 单线程致命问题

  1. 服务端主线程卡在Accept(),已有客户端发消息无法处理;

  2. 收发逻辑阻塞时,无法同时处理新客户端接入;

  3. 客户端 Receive 阻塞,无法手动输入新消息发送;

  4. 单个客户端断开会直接导致整个服务端程序崩溃。

3. 解决方案:多线程分离收发逻辑

概念

每一条客户端连接分配独立子线程处理收发,子线程内部阻塞不会干扰主线程 / 其他客户端;主线程仅负责监听新连接。

运行逻辑
  1. 主线程循环 Accept 捕获新客户端 Socket;

  2. 每拿到客户端套接字,新建线程专门处理该客户端消息收发;

  3. 子线程内循环 Receive、业务处理,阻塞仅影响自身线程。

代码片段(多线程服务端基础)

// 单个客户端独立消息处理线程 static void ClientHandle(Socket clientSocket){ byte[] buffer = new byte[1024]; while (true){ int len = clientSocket.Receive(buffer); if (len <= 0){ // 客户端断开连接 Console.WriteLine("客户端下线"); clientSocket.Close(); break; } string msg = System.Text.Encoding.UTF8.GetString(buffer, 0, len); Console.WriteLine("收到消息:" + msg); // 回发消息 byte[] sendBuf = System.Text.Encoding.UTF8.GetBytes("服务端已收到:" + msg); clientSocket.Send(sendBuf); } } // 服务主线程 static void Main(){ Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ep = new IPEndPoint(IPAddress.Any, 8080); server.Bind(ep); server.Listen(100); Console.WriteLine("服务端启动,等待连接..."); while (true){ Socket client = server.Accept(); // 主线程仅阻塞监听 // 新开线程处理客户端,互不阻塞 new Thread(() => ClientHandle(client)).Start(); Console.WriteLine("新客户端接入"); } }

四、通用网络 DLL 库封装(项目复用核心)

1. 封装目的

  1. 分离网络底层代码与业务逻辑,服务端控制台、Unity 客户端共用同一套网络逻辑;

  2. 避免每个项目重复编写 Socket 连接、收发、编码代码;

  3. 统一异常处理、断线检测,减少重复 bug。

2. VS 项目区分

控制台程序:输出 exe 可执行程序,独立运行;

类库项目(Class Library):输出.dll动态链接库,无 Main 入口,仅提供可调用类;

3. 库分层规范(命名空间隔离)

  1. MyNet.Server:TCP 服务端封装类

  2. MyNet.Client:TCP 客户端封装类

4. 服务端封装类完整结构

using System; using System.Net; using System.Net.Sockets; using System.Threading; ​ namespace MyNet.Server{ public class TcpServer{ private Socket _serverSocket; private int _port; // 构造函数:绑定指定端口 public TcpServer(int port){ _port = port; _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ep = new IPEndPoint(IPAddress.Any, _port); _server.Bind(ep); } // 启动监听,主线程阻塞监听,新连接开子线程 public void Start(){ _serverSocket.Listen(100); Console.WriteLine($"服务端启动,端口{_port}"); while (true){ Socket client = _serverSocket.Accept(); Thread t = new Thread(() => HandleClient(client)); t.IsBackground = true; t.Start(); } } // 单个客户端消息循环处理 private void HandleClient(Socket client){ byte[] buf = new byte[1024]; while (true){ int recvLen; try{ recvLen = client.Receive(buf); } catch{ break; } if (recvLen <= 0) break; string msg = Encoding.UTF8.GetString(buf, 0, recvLen); Console.WriteLine("客户端消息:" + msg); // 回包逻辑 byte[] send = Encoding.UTF8.GetBytes($"服务回复:{msg}"); client.Send(send); } client.Close(); Console.WriteLine("客户端断开连接"); } } }

5. 客户端封装类核心结构

namespace MyNet.Client{ public class TcpClient{ private Socket _clientSocket; private string _ip; private int _port; public TcpClient(string ip, int port){ _ip = ip; _port = port; _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } // 建立连接(底层自动三次握手) public bool Connect(){ try{ IPEndPoint ep = new IPEndPoint(IPAddress.Parse(_ip), _port); _clientSocket.Connect(ep); // 新开线程持续接收服务端推送消息 new Thread(RecvLoop).Start(); return true; } catch{ Console.WriteLine("连接失败"); return false; } } // 发送字符串消息封装 public void SendMsg(string msg){ byte[] data = Encoding.UTF8.GetBytes(msg); _clientSocket.Send(data); } // 后台持续接收消息 private void RecvLoop(){ byte[] buf = new byte[1024]; while (true){ int len = _clientSocket.Receive(buf); if (len <= 0) break; string res = Encoding.UTF8.GetString(buf, 0, len); Console.WriteLine("服务端返回:" + res); } } // 主动关闭连接,触发四次挥手 public void Close(){ _clientSocket.Close(); } } }

6. DLL 使用方式

  1. 编译类库项目生成MyNet.dll;

  2. 控制台 / Unity 项目右键引用该 dll;

  3. 头部添加using MyNet.Server;直接实例化类调用方法。

五、字符串与字节数组转换规范

1. 转换核心类:System.Text.Encoding.UTF8

发送:字符串 → byte 数组
string text = "玩家登录"; byte[] sendBuffer = Encoding.UTF8.GetBytes(text); socket.Send(sendBuffer);
接收:byte 数组 → 字符串

Receive 返回的len是实际收到字节长度,必须截取有效字节,避免多余空字符

byte[] recvBuf = new byte[1024]; int realLen = socket.Receive(recvBuf); string res = Encoding.UTF8.GetString(recvBuf, 0, realLen);

拓展:统一编码规范

项目全部使用 UTF8,避免 GBK/Unicode 混用导致中文乱码。

六、网络异常与断线容错处理

1. 崩溃根源

客户端强制关闭、网络波动时Receive()、Send()会抛出 Socket 异常,无 try-catch 捕获直接程序终止。

2. 标准容错方案

所有 Socket 读写操作包裹try-catch,捕获异常后主动关闭套接字、退出循环。

容错代码示例

private void HandleClient(Socket client){ byte[] buf = new byte[1024]; while (true){ int len; try{ len = client.Receive(buf); } catch (SocketException ex){ Console.WriteLine("网络异常:" + ex.Message); break; } if (len <= 0) break; // 业务处理逻辑 } client.Close(); }

七、实战交互流程(控制台长连接聊天)

  1. 启动服务端 TcpServer,开始监听端口;

  2. 客户端调用Connect()建立 TCP 长连接,三次握手完成;

  3. 客户端控制台输入文字,调用SendMsg()发送;

  4. 服务端子线程收到消息,自动回复;

  5. 客户端后台线程持续打印服务端回复;

  6. 客户端调用Close()主动断开,执行四次挥手正常释放资源。

八、重点

  1. TCP 三次握手每一步报文、作用,为什么不能两次握手;

  2. TCP 四次挥手完整流程,为什么不能三次关闭;

  3. Connect/Accept/Receive阻塞带来的单线程缺陷,多线程解决方案;

  4. 类库 DLL 封装优势,服务端 / 客户端分层设计;

  5. Socket 收发字节数组编码转换,UTF8 使用规范;

  6. 客户端异常下线程序崩溃解决方案(try-catch + 线程隔离);

  7. IPAddress.Any 与 127.0.0.1 区别:Any 监听本机所有网卡,仅本地测试用回环地址。

相关新闻

  • ComfyUI单图生成3D模型:混元3D+MV-Adapter低显存方案
  • AI Agent vs LLM:面试官最怕你只说“会调用工具”!深度解析本质区别与底层逻辑
  • 2026顶尖EMBA对比:五大优质项目综合实力评测榜单

最新新闻

  • 兴庆区口碑好的斜视训练的眼视光中心
  • Hermes Agent本地抓包指南:微信小程序协议分析与调试
  • AutoGLM安卓端侧部署:手机本地运行大模型全指南
  • 小学阶段如何科学开展孩子视力养护?2026 护眼参考维度附专业测评数据
  • 多模态宏观推演模型:世界黄金协会年中展望解析,下半年金价区间震荡的智能预测框架
  • 京东JoyAI UGC数字人:一张照片+语音创建专属虚拟玩伴

日新闻

  • Android逆向分析全能助手:集成化工具链与自动化工作流设计
  • 面搜索(Faceted Search)原理与工程实践指南
  • 神经网络调参避坑指南:从5个常见Loss曲线形态定位超参数问题

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号