作为现代网络通信的基石,TCP和UDP协议是开发者必须掌握的核心知识。本文将从协议原理、适用场景、C#实现三个维度全面解析两者差异,并通过10个代码示例展示如何用C#构建高效网络应用。
// TCP服务端
using System.Net;
using System.Net.Sockets;
TcpListener server = new TcpListener(IPAddress.Any, 8888);
server.Start();
while (true)
{
TcpClient client = server.AcceptTcpClient(); // 阻塞等待连接
NetworkStream stream = client.GetStream();
// 接收数据
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
string request = Encoding.UTF8.GetString(buffer, 0, bytesRead);
// 发送响应
string response = $"Received: {request}";
byte[] data = Encoding.UTF8.GetBytes(response);
stream.Write(data, 0, data.Length);
stream.Close();
client.Close();
}
// TCP客户端
using (TcpClient client = new TcpClient("127.0.0.1", 8888))
using (NetworkStream stream = client.GetStream())
{
string message = "Hello TCP!";
byte[] data = Encoding.UTF8.GetBytes(message);
stream.Write(data, 0, data.Length); // 发送数据
// 接收响应
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, bytesRead));
}
// UDP接收端
UdpClient receiver = new UdpClient(9999);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] data = receiver.Receive(ref remoteEP); // 阻塞接收
string message = Encoding.UTF8.GetString(data);
Console.WriteLine($"From {remoteEP}: {message}");
}
// UDP发送端
UdpClient sender = new UdpClient();
IPEndPoint targetEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999);
string message = "Hello UDP!";
byte[] data = Encoding.UTF8.GetBytes(message);
sender.Send(data, data.Length, targetEP); // 无连接直接发送
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接(三次握手) | 无连接 |
可靠性 | 保证数据完整性和顺序 | 可能丢包、乱序 |
传输效率 | 较高延迟(约100ms) | 极低延迟(约10ms) |
头部开销 | 20~60字节 | 8字节固定 |
典型应用 | 文件传输、Web服务 | 视频流、在线游戏 |
// 异步TCP服务端
TcpListener server = new TcpListener(IPAddress.Any, 8888);
server.Start();
while (true)
{
TcpClient client = await server.AcceptTcpClientAsync();
_ = HandleClientAsync(client);
}
async Task HandleClientAsync(TcpClient client)
{
using (NetworkStream stream = client.GetStream())
{
byte[] buffer = new byte[1024];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
// 处理业务逻辑...
}
}
// 加入组播组
UdpClient receiver = new UdpClient(9999);
receiver.JoinMulticastGroup(IPAddress.Parse("224.0.0.100"));
// 发送组播消息
UdpClient sender = new UdpClient();
sender.JoinMulticastGroup(IPAddress.Parse("224.0.0.100"));
byte[] data = Encoding.UTF8.GetBytes("Group Message");
sender.Send(data, data.Length, new IPEndPoint(IPAddress.Parse("224.0.0.100"), 9999));
TCP粘包处理
使用固定头(如4字节长度前缀)标识数据包边界:
// 发送带长度头的数据
byte[] payload = Encoding.UTF8.GetBytes("Data");
byte[] lengthHeader = BitConverter.GetBytes(payload.Length);
stream.Write(lengthHeader, 0, 4);
stream.Write(payload, 0, payload.Length);
UDP最大传输单元
单个数据包建议不超过1472字节(1500 MTU - 20 IP头 - 8 UDP头)
资源释放
务必使用using
语句或手动关闭连接:
// 正确释放资源
client.Close();
stream.Dispose();
graph TD
A[需要可靠传输?] -->|是| B[需要低延迟?]
A -->|否| C[选择UDP]
B -->|是| D[使用TCP优化(如QUIC)]
B -->|否| E[选择TCP]
C --> F[视频/语音/游戏]
E --> G[文件/邮件/数据库]
TCP与UDP的差异本质在于可靠性与效率的权衡:
C#通过System.Net.Sockets
命名空间提供了完整的协议支持,开发者应根据具体业务需求灵活选择协议类型,并通过异步编程、粘包处理等技巧构建高性能网络应用。