文章目录
一、TCP与UDP协议特点
1、TCP协议特点
特点 | 说明 |
---|---|
面向连接 | 通信前需通过三次握手建立连接,确保双方准备就绪 |
可靠性 | 通过序列号、确认应答、超时重传等机制保证数据完整有序到达 |
流量控制 | 自动调整传输速率避免网络拥塞 |
适用场景 | 卡牌类、棋牌类、回合制等对数据完整性要求高的游戏 |
2、UDP协议特点
特点 | 说明 |
---|---|
无连接 | 通信前需通过三次握手建立连接,确保双方准备就绪 |
高效性 | 通过序列号、确认应答、超时重传等机制保证数据完整有序到达 |
不可靠 | 自动调整传输速率避免网络拥塞 |
适用场景 | 实时性要求高的游戏如FPS、MOBA等 |
3、协议对比
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接 | 无连接 |
可靠性 | 高 | 低 |
传输速度 | 较慢 | 快 |
数据顺序 | 保证 | 不保证 |
流量控制 | 有 | 无 |
头部大小 | 20字节 | 8字节 |
使用场景 | 数据完整性优先 | 实时性优先 |
二、TCP与UDP协议实现
1、TCP通信实现
1、TCP服务端实现
csharp
using System.Net;
using System.Net.Sockets;
using System.Text;
class TCPServer
{
static void Main()
{
// 1. 创建TCP Socket
Socket tcpServer = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
// 2. 绑定IP和端口
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
tcpServer.Bind(endpoint);
// 3. 开始监听
tcpServer.Listen(10);
Console.WriteLine("服务器启动完成");
// 4. 接受客户端连接
Socket clientSocket = tcpServer.Accept();
Console.WriteLine("客户端已连接");
// 5. 接收数据
byte[] data = new byte[1024];
int length = clientSocket.Receive(data);
string message = Encoding.UTF8.GetString(data, 0, length);
Console.WriteLine("收到消息: " + message);
// 6. 发送数据
clientSocket.Send(Encoding.UTF8.GetBytes("服务器已收到"));
// 7. 关闭连接
clientSocket.Close();
tcpServer.Close();
}
}
2、TCP客户端实现
csharp
using System.Net;
using System.Net.Sockets;
using System.Text;
class TCPClient
{
static void Main()
{
// 1. 创建TCP Socket
//SocketType.Stream 对应面向连接的TCP协议
Socket tcpClient = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
// 2. 连接服务器
tcpClient.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888));
// 3. 发送数据
tcpClient.Send(Encoding.UTF8.GetBytes("Hello Server"));
// 4. 接收响应
byte[] data = new byte[1024];
int length = tcpClient.Receive(data);
Console.WriteLine("服务器响应: " + Encoding.UTF8.GetString(data, 0, length));
// 5. 关闭连接
tcpClient.Close();
}
}
2、UDP通信实现
1、UDP服务端实现
csharp
using System.Net;
using System.Net.Sockets;
using System.Text;
class UDPServer
{
static void Main()
{
// 1. 创建UDP Socket
// SocketType.Dgram 对应无连接的UDP协议
Socket udpServer = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
// 2. 绑定端口
udpServer.Bind(new IPEndPoint(IPAddress.Any, 8889));
Console.WriteLine("UDP服务器已启动");
// 3. 接收数据
//UDP接收响应必须有端口号,但可通过设为0由系统自动分配
EndPoint clientEnd = new IPEndPoint(IPAddress.Any, 0);
byte[] data = new byte[1024];
int length = udpServer.ReceiveFrom(data, ref clientEnd);
string message = Encoding.UTF8.GetString(data, 0, length);
Console.WriteLine($"收到来自{clientEnd}的消息: {message}");
// 4. 发送响应
udpServer.SendTo(Encoding.UTF8.GetBytes("UDP服务器已收到"), clientEnd);
// 5. 关闭Socket
udpServer.Close();
}
}
2、UDP客户端实现
csharp
using System.Net;
using System.Net.Sockets;
using System.Text;
class UDPClient
{
static void Main()
{
// 1. 创建UDP Socket
Socket udpClient = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
// 2. 发送数据
IPEndPoint serverEnd = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8889);
udpClient.SendTo(Encoding.UTF8.GetBytes("Hello UDP Server"), serverEnd);
// 3. 接收响应
//UDP接收响应必须有端口号,但可通过设为0由系统自动分配
byte[] data = new byte[1024];
EndPoint remoteEnd = new IPEndPoint(IPAddress.Any, 0);
int length = udpClient.ReceiveFrom(data, ref remoteEnd);
Console.WriteLine($"收到来自{remoteEnd}的响应: {Encoding.UTF8.GetString(data, 0, length)}");
// 4. 关闭Socket
udpClient.Close();
}
}
3、实现对比
特性 | TCP实现 | UDP实现 |
---|---|---|
Scoket创建 | SocketType.Stream,ProtocolType.Tcp | SocketType.Dgram,ProtocolType.Udp |
连接管理 | 需要Connect()/Accept()建立连接 | 无连接,直接发送数据 |
数据传输 | Send()/Receive() | SendTo()/ReceiveFrom() |
错误处理 | 处理连接中断,超时重传等 | 主要处理端口不可达等 |
三、TCPListener与UdpClient
1、TCPListener使用
TCPListener是对Socket的高级封装,简化了TCP服务端的创建过程:
csharp
using System.Net;
using System.Net.Sockets;
class TCPListenerExample
{
static void Main()
{
// 1. 创建TCPListener
TcpListener listener = new TcpListener(IPAddress.Any, 8888);
listener.Start();
Console.WriteLine("TCPListener已启动");
// 2. 接受客户端连接
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("客户端已连接");
// 3. 获取网络流
NetworkStream stream = client.GetStream();
// 4. 读取数据
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("收到消息: " + message);
// 5. 发送响应
byte[] response = Encoding.UTF8.GetBytes("TCPListener已收到");
stream.Write(response, 0, response.Length);
// 6. 关闭连接
client.Close();
listener.Stop();
}
}
2、UDPListener使用
UdpClient是对UDP Socket的高级封装,简化了UDP通信过程:
csharp
using System.Net;
using System.Net.Sockets;
class UdpClientExample
{
static void Main()
{
// 1. 创建UdpClient
UdpClient udpClient = new UdpClient(8888);
Console.WriteLine("UdpClient已启动");
// 2. 接收数据
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
byte[] receivedData = udpClient.Receive(ref remoteEP);
string message = Encoding.UTF8.GetString(receivedData);
Console.WriteLine($"收到来自{remoteEP}的消息: {message}");
// 3. 发送响应
byte[] response = Encoding.UTF8.GetBytes("UdpClient已收到");
udpClient.Send(response, response.Length, remoteEP);
// 4. 关闭UdpClient
udpClient.Close();
}
}
3、与Socket的对比
1、选择建议
1、使用TCPListener/UdpClient便于快速开发,适用简单通信需求,不需要特殊的Socket配置。
2、使用原生Socket需要精细控制网络行为,实现自定义协议,需要设置特殊Socket选项
2、实际应用建议
游戏类型选择:
回合制,卡牌类游戏优先选择TCP
实时动作类游戏优先选择UDP'
混合使用:
关键数据(如玩家状态)使用TCP
实时数据(如位置更新)使用UDP