Unity 网络编程传输层

初学者,自用笔记

TCP与UDP

TCP

面向连接:必须先建立连接才能通信

可靠传输:丢包会重传,保证数据不丢不乱

字节流:无边界,会产生粘包 / 拆包

拥塞控制 + 滑动窗口:保证网络不崩

全双工:双方可同时收发

三次握手:建立连接

c-s s-c c-s

四次挥手:断开连接

c-s s-c s-c c-s

UDP

无连接:快发

不可靠:可能丢包、乱序

数据报:有边界,无粘包

开销小、延迟低:适合实时游戏

alt

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

alt

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

alt

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();
    }
}
全部评论

相关推荐

zaakfung:26届不应该春招吗 为啥还实习
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务