当前位置: 首页 > news >正文

C# 中的 TCP 与 UDP 网络编程

在网络编程的世界里,TCP 和 UDP 就像两种不同的通信方式,支撑着我们日常使用的各类网络应用。

思维导图

一、网络编程基础认知

网络编程本质上是设备与设备之间通过网络进行数据传输,也常被称为 Socket(插座)编程。就像现实中两个人交流需要 “语言(协议)”、“地址(IP)”、“门牌号(端口)” 一样,网络编程也离不开三个核心要素:

1.协议:约束数据的传输格式,是设备间沟通的 “通用语言”;

2.IP 地址:标识数据要发送的目标设备,相当于 “收件人地址”;

3.端口:标识目标设备上的具体应用,相当于 “地址上的门牌号”。

在本地测试时,我们常用127.0.0.1localhost表示本机 IP;若要和局域网内其他电脑通信,则需使用真实 IP(如192.168.0.49)。

二、UDP 协议:“发短信式” 的无连接通信

2.1 UDP 核心特性

UDP 协议就像发短信 / 发微信消息:不需要提前和对方建立 “通话连接”,直接把消息发出去即可。它的核心特点可以总结为:

-无连接:通信前无需像打电话一样 “拨号建立连接”,发送端和接收端无逻辑绑定;

-不可靠:无法保证消息一定能送达(可能丢包),也无法保证消息顺序(比如先发的消息可能后到),就像短信可能因信号问题丢失;

-高效性:没有连接建立 / 维护的开销,协议头更小,传输延迟低,就像发短信比打电话更 “轻便”;

-面向数据报:数据以 “独立数据包” 为单位发送 / 接收,每个数据包都是完整的 “消息体”。

正因为这些特性,UDP 适合对实时性要求高、允许少量数据丢失的场景,比如在线游戏、音视频通话、DNS 查询、广播等。

2.2 C# 实现 UDP 通信(可直接拷贝测试)

2.2.1 基础通信:服务器(先收后发)+ 客户端(先发后收)
服务器端代码(先收后发)

c#

using System; using System.Net; using System.Net.Sockets; using System.Text; namespace UdpServer { internal class Program { static void Main(string[] args) { // 1. 创建UdpClient并绑定本地端点(IP+端口) IPAddress localIp = IPAddress.Loopback; // 本机IP IPEndPoint localEndPoint = new IPEndPoint(localIp, 8080); using (UdpClient udpClient = new UdpClient(localEndPoint)) { Console.WriteLine("UDP服务器已启动,等待客户端消息..."); // 2. 接收客户端数据(阻塞等待) IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); // 用于接收远程端点信息 byte[] receiveBytes = udpClient.Receive(ref remoteEndPoint); string receiveMsg = Encoding.Default.GetString(receiveBytes); Console.WriteLine($"收到客户端({remoteEndPoint})消息:{receiveMsg}"); // 3. 向客户端回复消息 string sendMsg = "收到,我是UDP服务器!"; byte[] sendBytes = Encoding.Default.GetBytes(sendMsg); udpClient.Send(sendBytes, sendBytes.Length, remoteEndPoint); Console.WriteLine("已向客户端发送回复"); } Console.ReadKey(); } } }
客户端代码(先发后收)

c#

using System; using System.Net; using System.Net.Sockets; using System.Text; namespace UdpClient { internal class Program { static void Main(string[] args) { // 1. 创建UdpClient(无需绑定端口,随机分配) using (UdpClient udpClient = new UdpClient()) { // 2. 向服务器发送消息 string sendMsg = "客户端请求:服务器,收到请回答!"; byte[] sendBytes = Encoding.Default.GetBytes(sendMsg); IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8080); // 服务器端点 udpClient.Send(sendBytes, sendBytes.Length, serverEndPoint); Console.WriteLine("已向服务器发送消息"); // 3. 接收服务器回复(阻塞等待) IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); byte[] receiveBytes = udpClient.Receive(ref remoteEndPoint); string receiveMsg = Encoding.Default.GetString(receiveBytes); Console.WriteLine($"收到服务器({remoteEndPoint})回复:{receiveMsg}"); } Console.ReadKey(); } } }
2.2.2 进阶:UDP 读写分离的聊天室(多线程)
客户端代码

c#

using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; namespace UDPChatClient { internal class Program { static void Main(string[] args) { // 绑定本地端口8080,用于接收服务器消息 IPAddress localIp = IPAddress.Loopback; IPEndPoint localEndPoint = new IPEndPoint(localIp, 8080); UdpClient udpClient = new UdpClient(localEndPoint); // 远程服务器端点(服务器绑定9999端口) IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Loopback, 9999); // 线程1:持续接收服务器消息 new Thread(() => { while (true) { byte[] receiveBytes = udpClient.Receive(ref serverEndPoint); string receiveMsg = Encoding.Default.GetString(receiveBytes); Console.WriteLine($"\n服务器:{receiveMsg}"); Console.Write("请输入要发送的内容:"); } }).Start(); // 线程2:持续发送消息给服务器 new Thread(() => { while (true) { Console.Write("请输入要发送的内容:"); string sendMsg = Console.ReadLine(); byte[] sendBytes = Encoding.Default.GetBytes(sendMsg); udpClient.Send(sendBytes, sendBytes.Length, serverEndPoint); } }).Start(); Console.ReadKey(); udpClient.Close(); } } }
服务器端代码

c#

using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; namespace UDPChatServer { internal class Program { static void Main(string[] args) { // 绑定本地端口9999,用于接收客户端消息 IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Loopback, 9999); UdpClient udpClient = new UdpClient(localEndPoint); // 远程客户端端点(客户端绑定8080端口) IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Loopback, 8080); // 线程1:持续发送消息给客户端 new Thread(() => { while (true) { Console.Write("请输入要发送的内容:"); string sendMsg = Console.ReadLine(); byte[] sendBytes = Encoding.Default.GetBytes(sendMsg); udpClient.Send(sendBytes, sendBytes.Length, clientEndPoint); } }).Start(); // 线程2:持续接收客户端消息 new Thread(() => { while (true) { byte[] receiveBytes = udpClient.Receive(ref clientEndPoint); string receiveMsg = Encoding.Default.GetString(receiveBytes); Console.WriteLine($"\n客户端:{receiveMsg}"); Console.Write("请输入要发送的内容:"); } }).Start(); Console.ReadKey(); udpClient.Close(); } } }

三、TCP 协议:“打电话式” 的可靠连接通信

3.1 TCP 核心特性

TCP 协议就像打电话:必须先拨通对方电话(三次握手建立连接),双方才能通话,通话结束后要挂电话(四次挥手断开连接)。它的核心特点是:

-面向连接:通信前必须通过 “三次握手” 建立逻辑连接,就像打电话要先确认对方接通;

-可靠性:通过确认应答、超时重传、序列号等机制,保证数据不丢失、不重复、不乱序,就像通话时能确保对方听清每一句话;

-基于字节流:数据是连续的字节序列,没有固定的 “消息边界”,需要应用层自己处理分包 / 粘包问题,就像通话时的连续语音;

-流量控制:通过滑动窗口机制控制发送速率,防止接收方缓冲区溢出,就像说话时会根据对方的回应调整语速。

TCP 适合对数据可靠性要求高的场景,比如文件传输、网页访问、即时聊天等。

3.2 TCP 连接的核心机制

-三次握手:确保双方都能收 / 发数据(客户端→服务器:我要连你;服务器→客户端:我知道你要连我,我也能连你;客户端→服务器:我知道你能连我,开始通信);

-四次挥手:确保双方都完成数据传输后断开连接(一方→另一方:我要断开;另一方→一方:我知道你要断开,等我发完剩余数据;另一方→一方:我发完了,你可以断了;一方→另一方:好的,断开)。

3.3 C# 实现 TCP 通信(可直接拷贝测试)

3.3.1 服务器端代码

c#

using System; using System.Net; using System.Net.Sockets; using System.Text; namespace TcpServer { internal class Program { static void Main(string[] args) { // 1. 创建TcpListener并绑定IP和端口 TcpListener listener = new TcpListener(IPAddress.Loopback, 8080); // 2. 启动监听 listener.Start(); Console.WriteLine("TCP服务器已启动,等待客户端连接..."); // 3. 接受客户端连接(阻塞方法,多客户端需用循环+线程) TcpClient tcpClient = listener.AcceptTcpClient(); IPEndPoint clientEndPoint = tcpClient.Client.RemoteEndPoint as IPEndPoint; Console.WriteLine($"客户端({clientEndPoint.Address}:{clientEndPoint.Port})已连接"); // 4. 获取网络流(用于读写数据) NetworkStream stream = tcpClient.GetStream(); // 5. 读取客户端发送的数据 byte[] receiveBuffer = new byte[1024]; int receiveLength = stream.Read(receiveBuffer, 0, receiveBuffer.Length); string receiveMsg = Encoding.Default.GetString(receiveBuffer, 0, receiveLength); Console.WriteLine($"客户端说:{receiveMsg}"); // 6. 向客户端发送回复 string sendMsg = "你好,我是TCP服务器!"; byte[] sendBuffer = Encoding.Default.GetBytes(sendMsg); stream.Write(sendBuffer, 0, sendBuffer.Length); Console.WriteLine("已向客户端发送回复"); // 7. 关闭资源(倒序关闭) stream.Close(); tcpClient.Close(); listener.Stop(); Console.ReadKey(); } } }
3.3.2 客户端代码

c#

using System; using System.Net.Sockets; using System.Text; namespace TcpClient { internal class Program { static void Main(string[] args) { // 1. 创建TcpClient对象 TcpClient tcpClient = new TcpClient(); // 2. 连接服务器(IP+端口) tcpClient.Connect("127.0.0.1", 8080); Console.WriteLine("已连接到TCP服务器"); // 3. 获取网络流 NetworkStream stream = tcpClient.GetStream(); // 4. 向服务器发送数据 string sendMsg = "你好,我是TCP客户端!"; byte[] sendBuffer = Encoding.Default.GetBytes(sendMsg); stream.Write(sendBuffer, 0, sendBuffer.Length); Console.WriteLine("已向服务器发送消息"); // 5. 读取服务器回复 byte[] receiveBuffer = new byte[1024]; int receiveLength = stream.Read(receiveBuffer, 0, receiveBuffer.Length); string receiveMsg = Encoding.Default.GetString(receiveBuffer, 0, receiveLength); Console.WriteLine($"服务器说:{receiveMsg}"); // 6. 关闭资源 stream.Close(); tcpClient.Close(); Console.ReadKey(); } } }

四、TCP 与 UDP 协议核心对比

表格

特性TCP 协议UDP 协议
连接性面向连接(三次握手建立连接)无连接(直接发送数据)
可靠性可靠(不丢包、有序、不重复)不可靠(可能丢包、乱序)
传输单位基于字节流(无消息边界)面向数据报(独立数据包)
效率低(有连接 / 重传开销)高(无额外开销)
流量控制支持(滑动窗口)不支持
适用场景文件传输、聊天、网页访问游戏、音视频、广播、DNS 查询
核心类(C#)TcpListener、TcpClient、NetworkStreamUdpClient、IPEndPoint

五、总结

TCP 和 UDP 作为网络编程的两大核心协议,没有绝对的优劣,只有 “适合与否”:

1. 若追求数据可靠性(如文件传输、关键信息通信),选 TCP;若追求实时性和效率(如游戏、音视频),选 UDP;

2. C# 对两种协议都提供了简洁的封装:UDP 用UdpClient+IPEndPoint,核心是 “数据报”;TCP 用TcpListener(服务端)+TcpClient(客户端)+NetworkStream,核心是 “连接 + 字节流”; 3. 实际开发中,UDP 常需上层协议补充可靠性(如游戏中的重传机制),TCP 需处理粘包 / 分包问题,需结合业务场景灵活调整。

http://www.jsqmd.com/news/474195/

相关文章:

  • 函数的递归
  • 游戏库管理困境?这款开源工具让Steam数据掌控变简单
  • IDEA或DataGrip手动插入数据时报错when IDENTITY_INSERT is set to OFF的解决方法
  • 告别编译烦恼:Vcpkg一站式部署Tesseract-OCR C++开发环境(Windows)
  • 如何用ncmdump突破网易云音乐格式限制:从原理到实践
  • Qwen1.5-1.8B GPTQ辅助数据库课程设计:智能ER图生成与SQL优化建议
  • 低显存也能玩转HY-Motion 1.0?优化技巧实测有效
  • Visual Components 5.0 全新升级,重构工业仿真体验,更高效、更智能、更贴近真实!
  • 开源天气平台自主部署全攻略:从数据集成到生产环境构建
  • 语音识别效果对比:清音听真1.7B如何吊打传统工具?
  • 电源变压器+常见拓扑科普:一文搞懂开关电源的核心架构
  • AI Agent 革命下的职业替代地图:哪些行业正在经历“结构性裁员“?
  • 解决多平台资源下载难题的全能工具:网络资源嗅探与批量获取指南
  • EcomGPT-7B基础教程:从start.sh启动到localhost:6006界面使用的完整流程
  • AIGlasses OS Pro 模型微调实战:针对特定数据集的优化训练
  • LangGraph 7. 技能 Skills
  • 【捕获WebSocket】基于CDP与Playwright增强Selenium测试中的实时消息验证
  • 革新资源解析:AssetStudio效率工具开发者必备指南
  • 1-13 T0-T4定时器测量脉冲时间
  • 告别IDA Pro:用Radare2图形化分析SO文件的5个高效技巧(含PEDA联动指南)
  • Vim寄存器实战指南——高效复制粘贴与剪切的秘密武器
  • AudioSeal Pixel Studio从零开始:Streamlit UI源码结构与Ocean Pixel Blue主题解析
  • BGE-Reranker-v2-m3部署成功率低?常见问题排查手册
  • 景石源:黄蜡石厂家的品质与服务优势
  • 规划计时器-备份(自己看)
  • Windows 11 24H2 LTSC 微软商店恢复方案:从功能缺失到生态完整
  • 3步释放显卡潜能:DLSS Swapper从技术原理到场景化应用的优化指南
  • Janus-Pro-7B企业应用:客服图文工单自动摘要+意图识别落地解析
  • 美胸-年美-造相Z-Turbo实战:为古籍修复师林晚生成角色立绘
  • VRRP安全认证:为什么你的网络需要它?(附详细实验配置)