Unity 网络编程传输层
初学者,自用笔记
TCP与UDP
TCP
面向连接:必须先建立连接才能通信
可靠传输:丢包会重传,保证数据不丢不乱
字节流:无边界,会产生粘包 / 拆包
拥塞控制 + 滑动窗口:保证网络不崩
全双工:双方可同时收发
三次握手:建立连接
c-s s-c c-s
四次挥手:断开连接
c-s s-c s-c c-s
UDP
无连接:快发
不可靠:可能丢包、乱序
数据报:有边界,无粘包
开销小、延迟低:适合实时游戏
Socket
// 所有网络消息基接口
public interface INetMessage { }
// 可靠消息标记:走 TCP
public interface IReliableMessage : INetMessage { }
// 不可靠消息标记:走 UDP
public interface IUnreliableMessage : INetMessage { }
// 客户端裸传输接口
public interface ITransportClient
{
void Connect(string ip, int port);
void Send(byte[] data);
void Close();
// 收到原始字节
event Action<byte[]> OnBytesReceived;
// 连接成功
event Action OnConnected;
// 连接关闭
event Action OnClosed;
}
// 服务端裸传输接口
public interface ITransportServer
{
void Start(string ip, int port);
void SendTo(EndPoint clientEP, byte[] data);
void Stop();
// 收到原始字节
event Action<byte[], EndPoint> OnBytesReceived;
// 客户端连接
event Action<EndPoint> OnClientConnected;
// 客户端断开
event Action<EndPoint> OnClientDisconnected;
}
TCP
TCPServer
// TCP服务端:只负责监听、接收、发送字节
public class TcpTransportServer : ITransportServer
{
private Socket _serverSocket;
private Thread _listenThread;
private readonly Dictionary<string, Socket> _clients = new();
private readonly object _lockObj = new object();
public event Action<byte[], EndPoint> OnBytesReceived;
public event Action<EndPoint> OnClientConnected;
public event Action<EndPoint> OnClientDisconnected;
// 启动监听
public void Start(string ip, int port)
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
_serverSocket.Listen(100);
_listenThread = new Thread(ListenLoop);
_listenThread.IsBackground = true;
_listenThread.Start();
}
// 接受客户端连接
private void ListenLoop()
{
while (true)
{
Socket client = _serverSocket.Accept();
EndPoint ep = client.RemoteEndPoint;
lock (_lockObj)
{
_clients[ep.ToString()] = client;
}
OnClientConnected?.Invoke(ep);
Thread thread = new Thread(() => ReceiveLoop(client));
thread.IsBackground = true;
thread.Start();
}
}
// 接收某个客户端的数据
private void ReceiveLoop(Socket client)
{
byte[] buffer = new byte[4096];
EndPoint ep = client.RemoteEndPoint;
try
{
while (true)
{
int len = client.Receive(buffer);
if (len == 0)
{
OnClientDisconnected?.Invoke(ep);
break;
}
byte[] chunk = new byte[len];
Array.Copy(buffer, 0, chunk, 0, len);
OnBytesReceived?.Invoke(chunk, ep);
}
}
catch
{
OnClientDisconnected?.Invoke(ep);
}
finally
{
try { client.Close(); } catch { }
}
}
// 发送字节给指定客户端
public void SendTo(EndPoint clientEP, byte[] data)
{
lock (_lockObj)
{
if (_clients.TryGetValue(clientEP.ToString(), out var client))
{
client.Send(data);
}
}
}
// 停止服务
public void Stop()
{
try { _serverSocket?.Close(); } catch { }
lock (_lockObj)
{
foreach (var c in _clients.Values)
try { c.Close(); } catch { }
_clients.Clear();
}
}
}
TCPClient
// TCP客户端:只负责收发字节
public class TcpTransportClient : ITransportClient
{
private Socket _socket;
private Thread _receiveThread;
private readonly byte[] _buffer = new byte[4096];
public event Action<byte[]> OnBytesReceived;
public event Action OnConnected;
public event Action OnClosed;
// 连接服务器
public void Connect(string ip, int port)
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
OnConnected?.Invoke();
// 启动接收线程
_receiveThread = new Thread(ReceiveLoop);
_receiveThread.IsBackground = true;
_receiveThread.Start();
}
// 发送字节
public void Send(byte[] data)
{
if (_socket == null || !_socket.Connected) return;
_socket.Send(data);
}
// 接收循环
private void ReceiveLoop()
{
try
{
while (true)
{
int len = _socket.Receive(_buffer);
if (len == 0)
{
OnClosed?.Invoke();
break;
}
byte[] chunk = new byte[len];
Array.Copy(_buffer, 0, chunk, 0, len);
OnBytesReceived?.Invoke(chunk);
}
}
catch
{
OnClosed?.Invoke();
}
}
// 关闭连接
public void Close()
{
try { _socket?.Close(); } catch { }
OnClosed?.Invoke();
}
}
UDP
UDPServer
// UDP服务端:只负责收发字节
public class UdpTransportServer : ITransportServer
{
private Socket _socket;
private Thread _receiveThread;
public event Action<byte[], EndPoint> OnBytesReceived;
public event Action<EndPoint> OnClientConnected;
public event Action<EndPoint> OnClientDisconnected;
// 启动监听
public void Start(string ip, int port)
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_socket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
_receiveThread = new Thread(ReceiveLoop);
_receiveThread.IsBackground = true;
_receiveThread.Start();
}
// 接收客户端数据
private void ReceiveLoop()
{
byte[] buffer = new byte[4096];
EndPoint ep = new IPEndPoint(IPAddress.Any, 0);
try
{
while (true)
{
int len = _socket.ReceiveFrom(buffer, ref ep);
if (len <= 0) continue;
OnClientConnected?.Invoke(ep);
byte[] chunk = new byte[len];
Array.Copy(buffer, 0, chunk, 0, len);
OnBytesReceived?.Invoke(chunk, ep);
}
}
catch
{
}
}
// 发送给客户端
public void SendTo(EndPoint clientEP, byte[] data)
{
_socket?.SendTo(data, clientEP);
}
// 停止服务
public void Stop()
{
try { _socket?.Close(); } catch { }
}
}
UDPClient
// UDP客户端:只负责收发字节
public class UdpTransportClient : ITransportClient
{
private Socket _socket;
private IPEndPoint _serverEP;
private Thread _receiveThread;
public event Action<byte[]> OnBytesReceived;
public event Action OnConnected;
public event Action OnClosed;
// 初始化目标服务端
public void Connect(string ip, int port)
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_serverEP = new IPEndPoint(IPAddress.Parse(ip), port);
OnConnected?.Invoke();
_receiveThread = new Thread(ReceiveLoop);
_receiveThread.IsBackground = true;
_receiveThread.Start();
}
// 发字节到服务端
public void Send(byte[] data)
{
if (_socket == null || _serverEP == null) return;
_socket.SendTo(data, _serverEP);
}
// 接收服务端返回
private void ReceiveLoop()
{
byte[] buffer = new byte[4096];
EndPoint ep = new IPEndPoint(IPAddress.Any, 0);
try
{
while (true)
{
int len = _socket.ReceiveFrom(buffer, ref ep);
if (len <= 0) continue;
byte[] chunk = new byte[len];
Array.Copy(buffer, 0, chunk, 0, len);
OnBytesReceived?.Invoke(chunk);
}
}
catch
{
OnClosed?.Invoke();
}
}
// 关闭
public void Close()
{
try { _socket?.Close(); } catch { }
OnClosed?.Invoke();
}
}
简单实例
服务端路由
// 服务端路由器
public interface ITransportRouterServer
{
void Start(string ip, int port);
void SendReliableTo(EndPoint clientEP, byte[] data);
void SendUnreliableTo(EndPoint clientEP, byte[] data);
void Stop();
event Action<byte[], EndPoint> OnReliableBytesReceived;
event Action<byte[], EndPoint> OnUnreliableBytesReceived;
event Action<EndPoint> OnClientConnected;
event Action<EndPoint> OnClientDisconnected;
}
// 服务端路由器:统一管理 TCP / UDP
public class TransportRouterServer : ITransportRouterServer
{
private readonly ITransportServer _tcp;
private readonly ITransportServer _udp;
public event Action<byte[], EndPoint> OnReliableBytesReceived;
public event Action<byte[], EndPoint> OnUnreliableBytesReceived;
public event Action<EndPoint> OnClientConnected;
public event Action<EndPoint> OnClientDisconnected;
// 注入 TCP / UDP 传输
public TransportRouterServer(ITransportServer tcp, ITransportServer udp)
{
_tcp = tcp;
_udp = udp;
// TCP 数据视为可靠来源
_tcp.OnBytesReceived += (bytes, ep) => OnReliableBytesReceived?.Invoke(bytes, ep);
// UDP 数据视为不可靠来源
_udp.OnBytesReceived += (bytes, ep) => OnUnreliableBytesReceived?.Invoke(bytes, ep);
// 连接事件转发
_tcp.OnClientConnected += ep => OnClientConnected?.Invoke(ep);
_udp.OnClientConnected += ep => OnClientConnected?.Invoke(ep);
_tcp.OnClientDisconnected += ep => OnClientDisconnected?.Invoke(ep);
_udp.OnClientDisconnected += ep => OnClientDisconnected?.Invoke(ep);
}
// 启动 TCP / UDP
public void Start(string ip, int port)
{
_tcp.Start(ip, port);
_udp.Start(ip, port);
}
// TCP 发可靠消息
public void SendReliableTo(EndPoint clientEP, byte[] data) => _tcp.SendTo(clientEP, data);
// UDP 发不可靠消息
public void SendUnreliableTo(EndPoint clientEP, byte[] data) => _udp.SendTo(clientEP, data);
// 停止
public void Stop()
{
_tcp.Stop();
_udp.Stop();
}
}
客户端路由
// 客户端路由器
public interface ITransportRouterClient
{
void Connect(string ip, int port);
void SendReliable(byte[] data);
void SendUnreliable(byte[] data);
void Close();
event Action<byte[]> OnReliableBytesReceived;
event Action<byte[]> OnUnreliableBytesReceived;
event Action OnConnected;
event Action OnClosed;
}
// 客户端路由器:统一管理 TCP / UDP
public class TransportRouterClient : ITransportRouterClient
{
private readonly ITransportClient _tcp;
private readonly ITransportClient _udp;
public event Action<byte[]> OnReliableBytesReceived;
public event Action<byte[]> OnUnreliableBytesReceived;
public event Action OnConnected;
public event Action OnClosed;
// 注入 TCP / UDP 传输
public TransportRouterClient(ITransportClient tcp, ITransportClient udp)
{
_tcp = tcp;
_udp = udp;
// TCP 数据视为可靠消息来源
_tcp.OnBytesReceived += bytes => OnReliableBytesReceived?.Invoke(bytes);
// UDP 数据视为不可靠消息来源
_udp.OnBytesReceived += bytes => OnUnreliableBytesReceived?.Invoke(bytes);
// 连接/关闭事件转发
_tcp.OnConnected += () => OnConnected?.Invoke();
_udp.OnConnected += () => OnConnected?.Invoke();
_tcp.OnClosed += () => OnClosed?.Invoke();
_udp.OnClosed += () => OnClosed?.Invoke();
}
// 同时建立 TCP / UDP
public void Connect(string ip, int port)
{
_tcp.Connect(ip, port);
_udp.Connect(ip, port);
}
// 发送可靠消息到 TCP
public void SendReliable(byte[] data) => _tcp.Send(data);
// 发送不可靠消息到 UDP
public void SendUnreliable(byte[] data) => _udp.Send(data);
// 同时关闭
public void Close()
{
_tcp.Close();
_udp.Close();
}
}
查看7道真题和解析