商业化游戏角色运动同步框架

实现一个高扩展、高性能、高可配置的C#语言的商业化游戏角色运动同步系统是一个复杂的任务。这个系统需要处理多个客户端之间的实时通信、数据同步、网络延迟、数据压缩等问题。以下是一个详细的实现,包括服务器端和客户端的代码。

1. 服务器端实现

1.1 配置管理

首先,我们需要一个配置管理器来管理服务器的配置。

Config/ConfigManager.cs:

using System.IO;
using Newtonsoft.Json;

public class ConfigManager
{
    private static ConfigManager _instance;
    public static ConfigManager Instance => _instance ?? (_instance = new ConfigManager());

    public ServerConfig Config { get; private set; }

    private ConfigManager() { }

    public void LoadConfig(string filePath)
    {
        var json = File.ReadAllText(filePath);
        Config = JsonConvert.DeserializeObject<ServerConfig>(json);
    }
}

public class ServerConfig
{
    public string IpAddress { get; set; }
    public int Port { get; set; }
    public int MaxConnections { get; set; }
    public int TickRate { get; set; }
}
1.2 日志记录

我们需要一个日志记录器来记录服务器的运行状态。

Logging/Logger.cs:

using System;
using System.IO;

public class Logger
{
    private static Logger _instance;
    public static Logger Instance => _instance ?? (_instance = new Logger());

    private StreamWriter _logWriter;

    private Logger() { }

    public void Initialize(string logFilePath)
    {
        _logWriter = new StreamWriter(logFilePath, true) { AutoFlush = true };
    }

    public void LogInfo(string message)
    {
        Log("INFO", message);
    }

    public void LogError(string message)
    {
        Log("ERROR", message);
    }

    private void Log(string level, string message)
    {
        var logMessage = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{level}] {message}";
        Console.WriteLine(logMessage);
        _logWriter.WriteLine(logMessage);
    }
}
1.3 网络通信

我们需要一个网络通信管理器来处理客户端的连接和数据传输。

Networking/NetworkManager.cs:

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class NetworkManager
{
    private TcpListener _listener;
    private ConcurrentDictionary<int, TcpClient> _clients;
    private int _clientIdCounter;

    public event Action<int, byte[]> OnDataReceived;

    public NetworkManager()
    {
        _clients = new ConcurrentDictionary<int, TcpClient>();
        _clientIdCounter = 0;
    }

    public void Start(string ipAddress, int port)
    {
        _listener = new TcpListener(IPAddress.Parse(ipAddress), port);
        _listener.Start();
        Logger.Instance.LogInfo($"Server started on {ipAddress}:{port}");

        Thread acceptThread = new Thread(AcceptClients);
        acceptThread.Start();
    }

    private void AcceptClients()
    {
        while (true)
        {
            var client = _listener.AcceptTcpClient();
            int clientId = Interlocked.Increment(ref _clientIdCounter);
            _clients[clientId] = client;
            Logger.Instance.LogInfo($"Client {clientId} connected");

            Thread receiveThread = new Thread(() => ReceiveData(clientId, client));
            receiveThread.Start();
        }
    }

    private void ReceiveData(int clientId, TcpClient client)
    {
        NetworkStream stream = client.GetStream();
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = stream.Read(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                OnDataReceived?.Invoke(clientId, data);
            }
            catch (Exception ex)
            {
                Logger.Instance.LogError($"Error receiving data from client {clientId}: {ex.Message}");
                break;
            }
        }

        _clients.TryRemove(clientId, out _);
        client.Close();
        Logger.Instance.LogInfo($"Client {clientId} disconnected");
    }

    public void SendData(int clientId, byte[] data)
    {
        if (_clients.TryGetValue(clientId, out TcpClient client))
        {
            NetworkStream stream = client.GetStream();
            stream.Write(data, 0, data.Length);
        }
    }

    public void Stop()
    {
        _listener.Stop();
        foreach (var client in _clients.Values)
        {
            client.Close();
        }
        _clients.Clear();
    }
}
1.4 角色管理

我们需要一个角色管理器来管理游戏中的角色。

Game/PlayerManager.cs:

using System.Collections.Concurrent;
using System.Collections.Generic;

public class PlayerManager
{
    private ConcurrentDictionary<int, Player> _players;

    public PlayerManager()
    {
        _players = new ConcurrentDictionary<int, Player>();
    }

    public void AddPlayer(int clientId, Player player)
    {
        _players[clientId] = player;
    }

    public void RemovePlayer(int clientId)
    {
        _players.TryRemove(clientId, out _);
    }

    public Player GetPlayer(int clientId)
    {
        _players.TryGetValue(clientId, out Player player);
        return player;
    }

    public IEnumerable<Player> GetAllPlayers()
    {
        return _players.Values;
    }
}

public class Player
{
    public int Id { get; set; }
    public string Name { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
    public float Z { get; set; }
}
1.5 运动同步

我们需要一个运动同步管理器来处理角色的运动同步。

Game/MovementSyncManager.cs:

using System;
using System.Text;

public class MovementSyncManager
{
    private PlayerManager _playerManager;
    private NetworkManager _networkManager;

    public MovementSyncManager(PlayerManager playerManager, NetworkManager networkManager)
    {
        _playerManager = playerManager;
        _networkManager = networkManager;
        _networkManager.OnDataReceived += OnDataReceived;
    }

    private void OnDataReceived(int clientId, byte[] data)
    {
        string message = Encoding.UTF8.GetString(data);
        string[] parts = message.Split(',');

        if (parts[0] == "MOVE")
        {
            float x = float.Parse(parts[1]);
            float y = float.Parse(parts[2]);
            float z = float.Parse(parts[3]);

            Player player = _playerManager.GetPlayer(clientId);
            if (player != null)
            {
                player.X = x;
                player.Y = y;
                player.Z = z;

                BroadcastMovement(player);
            }
        }
    }

    private void BroadcastMovement(Player player)
    {
        string message = $"MOVE,{player.Id},{player.X},{player.Y},{player.Z}";
        byte[] data = Encoding.UTF8.GetBytes(message);

        foreach (var otherPlayer in _playerManager.GetAllPlayers())
        {
            if (otherPlayer.Id != player.Id)
            {
                _networkManager.SendData(otherPlayer.Id, data);
            }
        }
    }
}
1.6 服务器主程序

最后,我们需要一个主程序来启动服务器。

Program.cs:

using System;

class Program
{
    static void Main(string[] args)
    {
        // 加载配置
        ConfigManager.Instance.LoadConfig("config.json");

        // 初始化日志记录
        Logger.Instance.Initialize("server.log");

        // 初始化网络管理
        NetworkManager networkManager = new NetworkManager();
        networkManager.Start(ConfigManager.Instance.Config.IpAddress, ConfigManager.Instance.Config.Port);

        // 初始化角色管理
        PlayerManager playerManager = new PlayerManager();

        // 初始化运动同步管理
        MovementSyncManager movementSyncManager = new MovementSyncManager(playerManager, networkManager);

        // 等待用户输入以停止服务器
        Console.WriteLine("Press Enter to stop the server...");
        Console.ReadLine();

        // 停止网络管理
        networkManager.Stop();
    }
}

2. 客户端实现

2.1 网络通信

我们需要一个网络通信管理器来处理与服务器的连接和数据传输。

Networking/NetworkManager.cs:

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class NetworkManager
{
    private TcpClient _client;
    private NetworkStream _stream;

    public event Action<byte[]> OnDataReceived;

    public void Connect(string ipAddress, int port)
    {
        _client = new TcpClient();
        _client.Connect(ipAddress, port);
        _stream = _client.GetStream();

        Thread receiveThread = new Thread(ReceiveData);
        receiveThread.Start();
    }

    private void ReceiveData()
    {
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = _stream.Read(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                OnDataReceived?.Invoke(data);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error receiving data: {ex.Message}");
                break;
            }
        }

        _client.Close();
    }

    public void SendData(byte[] data)
    {
        _stream.Write(data, 0, data.Length);
    }

    public void Disconnect()
    {
        _client.Close();
    }
}
2.2 角色管理

我们需要一个角色管理器来管理客户端的角色。

Game/PlayerManager.cs:

using System.Collections.Generic;

public class PlayerManager
{
    private Dictionary<int, Player> _players;

    public PlayerManager()
    {
        _players = new Dictionary<int, Player>();
    }

    public void AddPlayer(int id, Player player)
    {
        _players[id] = player;
    }

    public void RemovePlayer(int id)
    {
        _players.Remove(id);
    }

    public Player GetPlayer(int id)
    {
        _players.TryGetValue(id, out Player player);
        return player;
    }

    public IEnumerable<Player> GetAllPlayers()
    {
        return _players.Values;
    }
}

public class Player
{
    public int Id { get; set; }
    public string Name { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
    public float Z { get; set; }
}
2.3 运动同步

我们需要一个运动同步管理器来处理角色的运动同步。

Game/MovementSyncManager.cs:

using System;
using System.Text;

public class MovementSyncManager
{
    private PlayerManager _playerManager;
    private NetworkManager _networkManager;

    public MovementSyncManager(PlayerManager playerManager, NetworkManager networkManager)
    {
        _playerManager = playerManager;
        _networkManager = networkManager;
        _networkManager.OnDataReceived += OnDataReceived;
    }

    private void OnDataReceived(byte[] data)
    {
        string message = Encoding.UTF8.GetString(data);
        string[] parts = message.Split(',');

        if (parts[0] == "MOVE")
        {
            int playerId = int.Parse(parts[1]);
            float x = float.Parse(parts[2]);
            float y = float.Parse(parts[3]);
            float z = float.Parse(parts[4]);

            Player player = _playerManager.GetPlayer(playerId);
            if (player != null)
            {
                player.X = x;
                player.Y = y;
                player.Z = z;
            }
            else
            {
                player = new Player { Id = playerId, X = x, Y = y, Z = z };
                _playerManager.AddPlayer(playerId, player);
            }
        }
    }

    public void SendMovement(float x, float y, float z)
    {
        string message = $"MOVE,{x},{y},{z}";
        byte[] data = Encoding.UTF8.GetBytes(message);
        _networkManager.SendData(data);
    }
}
2.4 客户端主程序

最后,我们需要一个主程序来启动客户端。

Program.cs:

using System;

class Program
{
    static void Main(string[] args)
    {
        // 初始化网络管理
        NetworkManager networkManager = new NetworkManager();
        networkManager.Connect("127.0.0.1", 8080);

        // 初始化角色管理
        PlayerManager playerManager = new PlayerManager();

        // 初始化运动同步管理
        MovementSyncManager movementSyncManager = new MovementSyncManager(playerManager, networkManager);

        // 模拟角色运动
        while (true)
        {
            Console.WriteLine("Enter new position (x y z):");
            string[] input = Console.ReadLine().Split(' ');
            float x = float.Parse(input[0]);
            float y = float.Parse(input[1]);
            float z = float.Parse(input[2]);

            movementSyncManager.SendMovement(x, y, z);
        }
    }
}

总结

通过以上实现,我们构建了一个高扩展、高性能、高可配置的C#语言的商业化游戏角色运动同步系统。这个系统包括服务器端和客户端的完整实现,涵盖了配置管理、日志记录、网络通信、角色管理和运动同步等功能。你可以根据具体需求继续扩展和优化这个实现,例如添加更多的功能、优化网络通信的性能等。希望这些示例和思路能对你有所帮助。

好的,接下来我们可以进一步扩展和优化这个系统。我们将添加以下功能:

  1. 心跳机制:确保客户端和服务器之间的连接是活跃的。
  2. 数据压缩:减少网络传输的数据量,提高传输效率。
  3. 网络延迟处理:处理网络延迟,确保运动同步的平滑性。
  4. 多线程优化:优化服务器的多线程处理,提高并发性能。

1. 心跳机制

心跳机制用于检测客户端和服务器之间的连接是否活跃。我们可以在服务器和客户端之间定期发送心跳包,如果一段时间内没有收到心跳包,则认为连接已断开。

1.1 服务器端心跳机制

Networking/NetworkManager.cs:

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class NetworkManager
{
    private TcpListener _listener;
    private ConcurrentDictionary<int, TcpClient> _clients;
    private ConcurrentDictionary<int, DateTime> _lastHeartbeat;
    private int _clientIdCounter;
    private Timer _heartbeatTimer;

    public event Action<int, byte[]> OnDataReceived;

    public NetworkManager()
    {
        _clients = new ConcurrentDictionary<int, TcpClient>();
        _lastHeartbeat = new ConcurrentDictionary<int, DateTime>();
        _clientIdCounter = 0;
    }

    public void Start(string ipAddress, int port)
    {
        _listener = new TcpListener(IPAddress.Parse(ipAddress), port);
        _listener.Start();
        Logger.Instance.LogInfo($"Server started on {ipAddress}:{port}");

        Thread acceptThread = new Thread(AcceptClients);
        acceptThread.Start();

        _heartbeatTimer = new Timer(CheckHeartbeats, null, 0, 5000);
    }

    private void AcceptClients()
    {
        while (true)
        {
            var client = _listener.AcceptTcpClient();
            int clientId = Interlocked.Increment(ref _clientIdCounter);
            _clients[clientId] = client;
            _lastHeartbeat[clientId] = DateTime.Now;
            Logger.Instance.LogInfo($"Client {clientId} connected");

            Thread receiveThread = new Thread(() => ReceiveData(clientId, client));
            receiveThread.Start();
        }
    }

    private void ReceiveData(int clientId, TcpClient client)
    {
        NetworkStream stream = client.GetStream();
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = stream.Read(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                OnDataReceived?.Invoke(clientId, data);

                // 更新心跳时间
                _lastHeartbeat[clientId] = DateTime.Now;
            }
            catch (Exception ex)
            {
                Logger.Instance.LogError($"Error receiving data from client {clientId}: {ex.Message}");
                break;
            }
        }

        _clients.TryRemove(clientId, out _);
        _lastHeartbeat.TryRemove(clientId, out _);
        client.Close();
        Logger.Instance.LogInfo($"Client {clientId} disconnected");
    }

    private void CheckHeartbeats(object state)
    {
        DateTime now = DateTime.Now;
        foreach (var kvp in _lastHeartbeat)
        {
            if ((now - kvp.Value).TotalSeconds > 10)
            {
                int clientId = kvp.Key;
                _clients.TryRemove(clientId, out TcpClient client);
                _lastHeartbeat.TryRemove(clientId, out _);
                client?.Close();
                Logger.Instance.LogInfo($"Client {clientId} timed out");
            }
        }
    }

    public void SendData(int clientId, byte[] data)
    {
        if (_clients.TryGetValue(clientId, out TcpClient client))
        {
            NetworkStream stream = client.GetStream();
            stream.Write(data, 0, data.Length);
        }
    }

    public void Stop()
    {
        _listener.Stop();
        foreach (var client in _clients.Values)
        {
            client.Close();
        }
        _clients.Clear();
        _heartbeatTimer.Dispose();
    }
}
1.2 客户端心跳机制

Networking/NetworkManager.cs:

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class NetworkManager
{
    private TcpClient _client;
    private NetworkStream _stream;
    private Timer _heartbeatTimer;

    public event Action<byte[]> OnDataReceived;

    public void Connect(string ipAddress, int port)
    {
        _client = new TcpClient();
        _client.Connect(ipAddress, port);
        _stream = _client.GetStream();

        Thread receiveThread = new Thread(ReceiveData);
        receiveThread.Start();

        _heartbeatTimer = new Timer(SendHeartbeat, null, 0, 5000);
    }

    private void ReceiveData()
    {
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = _stream.Read(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                OnDataReceived?.Invoke(data);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error receiving data: {ex.Message}");
                break;
            }
        }

        _client.Close();
    }

    private void SendHeartbeat(object state)
    {
        byte[] data = Encoding.UTF8.GetBytes("HEARTBEAT");
        _stream.Write(data, 0, data.Length);
    }

    public void SendData(byte[] data)
    {
        _stream.Write(data, 0, data.Length);
    }

    public void Disconnect()
    {
        _client.Close();
        _heartbeatTimer.Dispose();
    }
}

2. 数据压缩

为了减少网络传输的数据量,我们可以使用数据压缩技术。这里我们使用GZip进行数据压缩和解压缩。

2.1 数据压缩工具类

Utils/CompressionUtils.cs:

using System.IO;
using System.IO.Compression;

public static class CompressionUtils
{
    public static byte[] Compress(byte[] data)
    {
        using (var compressedStream = new MemoryStream())
        {
            using (var gzipStream = new GZipStream(compressedStream, CompressionMode.Compress))
            {
                gzipStream.Write(data, 0, data.Length);
            }
            return compressedStream.ToArray();
        }
    }

    public static byte[] Decompress(byte[] data)
    {
        using (var compressedStream = new MemoryStream(data))
        {
            using (var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
            {
                using (var decompressedStream = new MemoryStream())
                {
                    gzipStream.CopyTo(decompressedStream);
                    return decompressedStream.ToArray();
                }
            }
        }
    }
}
2.2 服务器端数据压缩

在服务器端发送和接收数据时进行压缩和解压缩。

Networking/NetworkManager.cs:

private void ReceiveData(int clientId, TcpClient client)
{
    NetworkStream stream = client.GetStream();
    byte[] buffer = new byte[1024];

    while (true)
    {
        try
        {
            int bytesRead = stream.Read(buffer, 0, buffer.Length);
            if (bytesRead == 0)
            {
                break;
            }

            byte[] data = new byte[bytesRead];
            Array.Copy(buffer, data, bytesRead);
            data = CompressionUtils.Decompress(data);
            OnDataReceived?.Invoke(clientId, data);

            // 更新心跳时间
            _lastHeartbeat[clientId] = DateTime.Now;
        }
        catch (Exception ex)
        {
            Logger.Instance.LogError($"Error receiving data from client {clientId}: {ex.Message}");
            break;
        }
    }

    _clients.TryRemove(clientId, out _);
    _lastHeartbeat.TryRemove(clientId, out _);
    client.Close();
    Logger.Instance.LogInfo($"Client {clientId} disconnected");
}

public void SendData(int clientId, byte[] data)
{
    if (_clients.TryGetValue(clientId, out TcpClient client))
    {
        NetworkStream stream = client.GetStream();
        data = CompressionUtils.Compress(data);
        stream.Write(data, 0, data.Length);
    }
}
2.3 客户端数据压缩

在客户端发送和接收数据时进行压缩和解压缩。

Networking/NetworkManager.cs:

private void ReceiveData()
{
    byte[] buffer = new byte[1024];

    while (true)
    {
        try
        {
            int bytesRead = _stream.Read(buffer, 0, buffer.Length);
            if (bytesRead == 0)
            {
                break;
            }

            byte[] data = new byte[bytesRead];
            Array.Copy(buffer, data, bytesRead);
            data = CompressionUtils.Decompress(data);
            OnDataReceived?.Invoke(data);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error receiving data: {ex.Message}");
            break;
        }
    }

    _client.Close();
}

public void SendData(byte[] data)
{
    data = CompressionUtils.Compress(data);
    _stream.Write(data, 0, data.Length);
}

3. 网络延迟处理

为了处理网络延迟,我们可以使用插值和外推技术来平滑角色的运动。这里我们使用简单的线性插值来处理网络延迟。

3.1 服务器端网络延迟处理

在服务器端,我们不需要做太多处理,只需要确保数据的及时发送。

3.2 客户端网络延迟处理

在客户端,我们需要对接收到的角色位置进行插值处理。

Game/Player.cs:

using System;

public class Player
{
    public int Id { get; set; }
    public string Name { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
    public float Z { get; set; }

    private float _targetX;
    private float _targetY;
    private float _targetZ;
    private float _lerpSpeed = 5.0f;

    public void SetTargetPosition(float x, float y, float z)
    {
        _targetX = x;
        _targetY = y;
        _targetZ = z;
    }

    public void Update(float deltaTime)
    {
        X = Mathf.Lerp(X, _targetX, _lerpSpeed * deltaTime);
        Y = Mathf.Lerp(Y, _targetY, _lerpSpeed * deltaTime);
        Z = Mathf.Lerp(Z, _targetZ, _lerpSpeed * deltaTime);
    }
}

public static class Mathf
{
    public static float Lerp(float a, float b, float t)
    {
        return a + (b - a) * t;
    }
}

Game/MovementSyncManager.cs:

private void OnDataReceived(byte[] data)
{
    string message = Encoding.UTF8.GetString(data);
    string[] parts = message.Split(',');

    if (parts[0] == "MOVE")
    {
        int playerId = int.Parse(parts[1]);
        float x = float.Parse(parts[2]);
        float y = float.Parse(parts[3]);
        float z = float.Parse(parts[4]);

        Player player = _playerManager.GetPlayer(playerId);
        if (player != null)
        {
            player.SetTargetPosition(x, y, z);
        }
        else
        {
            player = new Player { Id = playerId, X = x, Y = y, Z = z };
            _playerManager.AddPlayer(playerId, player);
        }
    }
}

4. 多线程优化

为了提高服务器的并发性能,我们可以使用线程池来处理客户端的连接和数据接收。

4.1 服务器端多线程优化

Networking/NetworkManager.cs:

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class NetworkManager
{
    private TcpListener _listener;
    private ConcurrentDictionary<int, TcpClient> _clients;
    private ConcurrentDictionary<int, DateTime> _lastHeartbeat;
    private int _clientIdCounter;
    private Timer _heartbeatTimer;

    public event Action<int, byte[]> OnDataReceived;

    public NetworkManager()
    {
        _clients = new ConcurrentDictionary<int, TcpClient>();
        _lastHeartbeat = new ConcurrentDictionary<int, DateTime>();
        _clientIdCounter = 0;
    }

    public void Start(string ipAddress, int port)
    {
        _listener = new TcpListener(IPAddress.Parse(ipAddress), port);
        _listener.Start();
        Logger.Instance.LogInfo($"Server started on {ipAddress}:{port}");

        Task.Run(() => AcceptClients());

        _heartbeatTimer = new Timer(CheckHeartbeats, null, 0, 5000);
    }

    private async Task AcceptClients()
    {
        while (true)
        {
            var client = await _listener.AcceptTcpClientAsync();
            int clientId = Interlocked.Increment(ref _clientIdCounter);
            _clients[clientId] = client;
            _lastHeartbeat[clientId] = DateTime.Now;
            Logger.Instance.LogInfo($"Client {clientId} connected");

            Task.Run(() => ReceiveData(clientId, client));
        }
    }

    private async Task ReceiveData(int clientId, TcpClient client)
    {
        NetworkStream stream = client.GetStream();
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                data = CompressionUtils.Decompress(data);
                OnDataReceived?.Invoke(clientId, data);

                // 更新心跳时间
                _lastHeartbeat[clientId] = DateTime.Now;
            }
            catch (Exception ex)
            {
                Logger.Instance.LogError($"Error receiving data from client {clientId}: {ex.Message}");
                break;
            }
        }

        _clients.TryRemove(clientId, out _);
        _lastHeartbeat.TryRemove(clientId, out _);
        client.Close();
        Logger.Instance.LogInfo($"Client {clientId} disconnected");
    }

    private void CheckHeartbeats(object state)
    {
        DateTime now = DateTime.Now;
        foreach (var kvp in _lastHeartbeat)
        {
            if ((now - kvp.Value).TotalSeconds > 10)
            {
                int clientId = kvp.Key;
                _clients.TryRemove(clientId, out TcpClient client);
                _lastHeartbeat.TryRemove(clientId, out _);
                client?.Close();
                Logger.Instance.LogInfo($"Client {clientId} timed out");
            }
        }
    }

    public void SendData(int clientId, byte[] data)
    {
        if (_clients.TryGetValue(clientId, out TcpClient client))
        {
            NetworkStream stream = client.GetStream();
            data = CompressionUtils.Compress(data);
            stream.Write(data, 0, data.Length);
        }
    }

    public void Stop()
    {
        _listener.Stop();
        foreach (var client in _clients.Values)
        {
            client.Close();
        }
        _clients.Clear();
        _heartbeatTimer.Dispose();
    }
}

总结

通过以上扩展和优化,我们进一步提高了系统的可靠性和性能。心跳机制确保了客户端和服务器之间的连接是活跃的,数据压缩减少了网络传输的数据量,网络延迟处理确保了运动同步的平滑性,多线程优化提高了服务器的并发性能。

你可以根据具体需求继续扩展和优化这个实现,例如添加更多的功能、优化网络通信的性能等。希望这些示例和思路能对你有所帮助。

好的,我们可以继续扩展和优化这个系统。接下来,我们将添加以下功能:

  1. 安全性增强:使用加密技术保护数据传输的安全性。
  2. 负载均衡:在多台服务器之间分配负载,提高系统的可扩展性和可靠性。
  3. 日志记录和监控:记录系统运行日志,并提供监控功能,便于运维和故障排查。

1. 安全性增强

为了保护数据传输的安全性,我们可以使用SSL/TLS加密。我们将使用.NET的SslStream类来实现这一功能。

1.1 服务器端SSL/TLS加密

Networking/NetworkManager.cs:

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class NetworkManager
{
    private TcpListener _listener;
    private ConcurrentDictionary<int, TcpClient> _clients;
    private ConcurrentDictionary<int, DateTime> _lastHeartbeat;
    private int _clientIdCounter;
    private Timer _heartbeatTimer;
    private X509Certificate2 _serverCertificate;

    public event Action<int, byte[]> OnDataReceived;

    public NetworkManager(string certificatePath, string certificatePassword)
    {
        _clients = new ConcurrentDictionary<int, TcpClient>();
        _lastHeartbeat = new ConcurrentDictionary<int, DateTime>();
        _clientIdCounter = 0;
        _serverCertificate = new X509Certificate2(certificatePath, certificatePassword);
    }

    public void Start(string ipAddress, int port)
    {
        _listener = new TcpListener(IPAddress.Parse(ipAddress), port);
        _listener.Start();
        Logger.Instance.LogInfo($"Server started on {ipAddress}:{port}");

        Task.Run(() => AcceptClients());

        _heartbeatTimer = new Timer(CheckHeartbeats, null, 0, 5000);
    }

    private async Task AcceptClients()
    {
        while (true)
        {
            var client = await _listener.AcceptTcpClientAsync();
            int clientId = Interlocked.Increment(ref _clientIdCounter);
            _clients[clientId] = client;
            _lastHeartbeat[clientId] = DateTime.Now;
            Logger.Instance.LogInfo($"Client {clientId} connected");

            Task.Run(() => HandleClient(clientId, client));
        }
    }

    private async Task HandleClient(int clientId, TcpClient client)
    {
        using (var sslStream = new SslStream(client.GetStream(), false))
        {
            try
            {
                await sslStream.AuthenticateAsServerAsync(_serverCertificate, false, System.Security.Authentication.SslProtocols.Tls12, true);
                await ReceiveData(clientId, sslStream);
            }
            catch (Exception ex)
            {
                Logger.Instance.LogError($"Error handling client {clientId}: {ex.Message}");
            }
        }

        _clients.TryRemove(clientId, out _);
        _lastHeartbeat.TryRemove(clientId, out _);
        client.Close();
        Logger.Instance.LogInfo($"Client {clientId} disconnected");
    }

    private async Task ReceiveData(int clientId, SslStream sslStream)
    {
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = await sslStream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                data = CompressionUtils.Decompress(data);
                OnDataReceived?.Invoke(clientId, data);

                // 更新心跳时间
                _lastHeartbeat[clientId] = DateTime.Now;
            }
            catch (Exception ex)
            {
                Logger.Instance.LogError($"Error receiving data from client {clientId}: {ex.Message}");
                break;
            }
        }
    }

    private void CheckHeartbeats(object state)
    {
        DateTime now = DateTime.Now;
        foreach (var kvp in _lastHeartbeat)
        {
            if ((now - kvp.Value).TotalSeconds > 10)
            {
                int clientId = kvp.Key;
                _clients.TryRemove(clientId, out TcpClient client);
                _lastHeartbeat.TryRemove(clientId, out _);
                client?.Close();
                Logger.Instance.LogInfo($"Client {clientId} timed out");
            }
        }
    }

    public void SendData(int clientId, byte[] data)
    {
        if (_clients.TryGetValue(clientId, out TcpClient client))
        {
            using (var sslStream = new SslStream(client.GetStream(), false))
            {
                data = CompressionUtils.Compress(data);
                sslStream.Write(data, 0, data.Length);
            }
        }
    }

    public void Stop()
    {
        _listener.Stop();
        foreach (var client in _clients.Values)
        {
            client.Close();
        }
        _clients.Clear();
        _heartbeatTimer.Dispose();
    }
}
1.2 客户端SSL/TLS加密

Networking/NetworkManager.cs:

using System;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class NetworkManager
{
    private TcpClient _client;
    private SslStream _sslStream;
    private Timer _heartbeatTimer;

    public event Action<byte[]> OnDataReceived;

    public void Connect(string ipAddress, int port)
    {
        _client = new TcpClient();
        _client.Connect(ipAddress, port);
        _sslStream = new SslStream(_client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);

        _sslStream.AuthenticateAsClient(ipAddress);

        Task.Run(() => ReceiveData());

        _heartbeatTimer = new Timer(SendHeartbeat, null, 0, 5000);
    }

    private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        // 在这里可以添加证书验证逻辑
        return true;
    }

    private async Task ReceiveData()
    {
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = await _sslStream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                data = CompressionUtils.Decompress(data);
                OnDataReceived?.Invoke(data);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error receiving data: {ex.Message}");
                break;
            }
        }

        _client.Close();
    }

    private void SendHeartbeat(object state)
    {
        byte[] data = Encoding.UTF8.GetBytes("HEARTBEAT");
        _sslStream.Write(data, 0, data.Length);
    }

    public void SendData(byte[] data)
    {
        data = CompressionUtils.Compress(data);
        _sslStream.Write(data, 0, data.Length);
    }

    public void Disconnect()
    {
        _client.Close();
        _heartbeatTimer.Dispose();
    }
}

2. 负载均衡

为了实现负载均衡,我们可以使用一个负载均衡器来在多台服务器之间分配负载。这里我们使用一个简单的轮询算法来实现负载均衡。

2.1 负载均衡器

Networking/LoadBalancer.cs:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

public class LoadBalancer
{
    private List<IPEndPoint> _serverEndpoints;
    private int _currentServerIndex;

    public LoadBalancer(List<IPEndPoint> serverEndpoints)
    {
        _serverEndpoints = serverEndpoints;
        _currentServerIndex = 0;
    }

    public async Task<TcpClient> AcceptClientAsync()
    {
        var serverEndpoint = GetNextServerEndpoint();
        var client = new TcpClient();
        await client.ConnectAsync(serverEndpoint.Address, serverEndpoint.Port);
        return client;
    }

    private IPEndPoint GetNextServerEndpoint()
    {
        var serverEndpoint = _serverEndpoints[_currentServerIndex];
        _currentServerIndex = (_currentServerIndex + 1) % _serverEndpoints.Count;
        return serverEndpoint;
    }
}
2.2 使用负载均衡器

在客户端连接时使用负载均衡器来选择服务器。

Networking/NetworkManager.cs:

public class NetworkManager
{
    private TcpClient _client;
    private SslStream _sslStream;
    private Timer _heartbeatTimer;
    private LoadBalancer _loadBalancer;

    public event Action<byte[]> OnDataReceived;

    public NetworkManager(List<IPEndPoint> serverEndpoints)
    {
        _loadBalancer = new LoadBalancer(serverEndpoints);
    }

    public async Task ConnectAsync()
    {
        _client = await _loadBalancer.AcceptClientAsync();
        _sslStream = new SslStream(_client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);

        await _sslStream.AuthenticateAsClientAsync(_client.Client.RemoteEndPoint.ToString());

        Task.Run(() => ReceiveData());

        _heartbeatTimer = new Timer(SendHeartbeat, null, 0, 5000);
    }

    private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        // 在这里可以添加证书验证逻辑
        return true;
    }

    private async Task ReceiveData()
    {
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = await _sslStream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                data = CompressionUtils.Decompress(data);
                OnDataReceived?.Invoke(data);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error receiving data: {ex.Message}");
                break;
            }
        }

        _client.Close();
    }

    private void SendHeartbeat(object state)
    {
        byte[] data = Encoding.UTF8.GetBytes("HEARTBEAT");
        _sslStream.Write(data, 0, data.Length);
    }

    public void SendData(byte[] data)
    {
        data = CompressionUtils.Compress(data);
        _sslStream.Write(data, 0, data.Length);
    }

    public void Disconnect()
    {
        _client.Close();
        _heartbeatTimer.Dispose();
    }
}

3. 日志记录和监控

为了便于运维和故障排查,我们需要记录系统运行日志,并提供监控功能。

3.1 日志记录

我们可以使用一个简单的日志记录器来记录系统运行日志。

Utils/Logger.cs:

using System;
using System.IO;

public class Logger
{
    private static Logger _instance;
    private StreamWriter _logWriter;

    private Logger()
    {
        _logWriter = new StreamWriter("log.txt", true);
        _logWriter.AutoFlush = true;
    }

    public static Logger Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new Logger();
            }
            return _instance;
        }
    }

    public void LogInfo(string message)
    {
        Log("INFO", message);
    }

    public void LogError(string message)
    {
        Log("ERROR", message);
    }

    private void Log(string level, string message)
    {
        string logMessage = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{level}] {message}";
        Console.WriteLine(logMessage);
        _logWriter.WriteLine(logMessage);
    }
}
3.2 监控功能

我们可以使用一个简单的监控工具来监控系统的运行状态。

Utils/Monitor.cs:

using System;
using System.Collections.Concurrent;
using System.Threading;

public class Monitor
{
    private ConcurrentDictionary<string, int> _metrics;
    private Timer _monitorTimer;

    public Monitor()
    {
        _metrics = new ConcurrentDictionary<string, int>();
        _monitorTimer = new Timer(LogMetrics, null, 0, 60000);
    }

    public void IncrementMetric(string metricName)
    {
        _metrics.AddOrUpdate(metricName, 1, (key, value) => value + 1);
    }

    private void LogMetrics(object state)
    {
        foreach (var kvp in _metrics)
        {
            Logger.Instance.LogInfo($"{kvp.Key}: {kvp.Value}");
        }
    }
}

总结

通过以上扩展和优化,我们进一步提高了系统的安全性、可扩展性和可靠性。SSL/TLS加密保护了数据传输的安全性,负载均衡在多台服务器之间分配负载,日志记录和监控功能便于运维和故障排查。

你可以根据具体需求继续扩展和优化这个实现,例如添加更多的安全措施、优化负载均衡算法、增强监控功能等。希望这些示例和思路能对你有所帮助。

好的,我们可以继续扩展和优化系统。接下来,我们将添加以下功能:

  1. 数据库集成:将数据存储到数据库中,以便持久化和查询。
  2. 缓存机制:使用缓存来提高系统性能。
  3. API接口:提供RESTful API接口,便于外部系统集成。

1. 数据库集成

我们将使用Entity Framework Core来集成数据库。首先,我们需要安装Entity Framework Core的NuGet包:

dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
1.1 数据库上下文

Data/ApplicationDbContext.cs:

using Microsoft.EntityFrameworkCore;

public class ApplicationDbContext : DbContext
{
    public DbSet<ClientData> ClientData { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("YourConnectionStringHere");
    }
}

public class ClientData
{
    public int Id { get; set; }
    public int ClientId { get; set; }
    public byte[] Data { get; set; }
    public DateTime Timestamp { get; set; }
}
1.2 数据库操作

Data/DatabaseManager.cs:

using System;
using System.Linq;

public class DatabaseManager
{
    private ApplicationDbContext _context;

    public DatabaseManager()
    {
        _context = new ApplicationDbContext();
    }

    public void SaveClientData(int clientId, byte[] data)
    {
        var clientData = new ClientData
        {
            ClientId = clientId,
            Data = data,
            Timestamp = DateTime.Now
        };
        _context.ClientData.Add(clientData);
        _context.SaveChanges();
    }

    public ClientData GetClientData(int clientId)
    {
        return _context.ClientData
            .Where(cd => cd.ClientId == clientId)
            .OrderByDescending(cd => cd.Timestamp)
            .FirstOrDefault();
    }
}
1.3 集成到网络管理器

Networking/NetworkManager.cs:

public class NetworkManager
{
    private TcpListener _listener;
    private ConcurrentDictionary<int, TcpClient> _clients;
    private ConcurrentDictionary<int, DateTime> _lastHeartbeat;
    private int _clientIdCounter;
    private Timer _heartbeatTimer;
    private X509Certificate2 _serverCertificate;
    private DatabaseManager _databaseManager;

    public event Action<int, byte[]> OnDataReceived;

    public NetworkManager(string certificatePath, string certificatePassword)
    {
        _clients = new ConcurrentDictionary<int, TcpClient>();
        _lastHeartbeat = new ConcurrentDictionary<int, DateTime>();
        _clientIdCounter = 0;
        _serverCertificate = new X509Certificate2(certificatePath, certificatePassword);
        _databaseManager = new DatabaseManager();
    }

    // 其他方法保持不变

    private async Task ReceiveData(int clientId, SslStream sslStream)
    {
        byte[] buffer = new byte[1024];

        while (true)
        {
            try
            {
                int bytesRead = await sslStream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                {
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                data = CompressionUtils.Decompress(data);
                OnDataReceived?.Invoke(clientId, data);

                // 更新心跳时间
                _lastHeartbeat[clientId] = DateTime.Now;

                // 保存数据到数据库
                _databaseManager.SaveClientData(clientId, data);
            }
            catch (Exception ex)
            {
                Logger.Instance.LogError($"Error receiving data from client {clientId}: {ex.Message}");
                break;
            }
        }
    }
}

2. 缓存机制

我们将使用MemoryCache来实现缓存机制,以提高系统性能。

2.1 缓存管理器

Utils/CacheManager.cs:

using System;
using Microsoft.Extensions.Caching.Memory;

public class CacheManager
{
    private static CacheManager _instance;
    private MemoryCache _cache;

    private CacheManager()
    {
        _cache = new MemoryCache(new MemoryCacheOptions());
    }

    public static CacheManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new CacheManager();
            }
            return _instance;
        }
    }

    public void Set(string key, object value, TimeSpan expiration)
    {
        _cache.Set(key, value, expiration);
    }

    public object Get(string key)
    {
        return _cache.TryGetValue(key, out var value) ? value : null;
    }
}
2.2 集成到数据库管理器

Data/DatabaseManager.cs:

public class DatabaseManager
{
    private ApplicationDbContext _context;
    private CacheManager _cacheManager;

    public DatabaseManager()
    {
        _context = new ApplicationDbContext();
        _cacheManager = CacheManager.Instance;
    }

    public void SaveClientData(int clientId, byte[] data)
    {
        var clientData = new ClientData
        {
            ClientId = clientId,
            Data = data,
            Timestamp = DateTime.Now
        };
        _context.ClientData.Add(clientData);
        _context.SaveChanges();

        // 更新缓存
        _cacheManager.Set($"ClientData_{clientId}", clientData, TimeSpan.FromMinutes(10));
    }

    public ClientData GetClientData(int clientId)
    {
        var cacheKey = $"ClientData_{clientId}";
        var cachedData = _cacheManager.Get(cacheKey) as ClientData;
        if (cachedData != null)
        {
            return cachedData;
        }

        var clientData = _context.ClientData
            .Where(cd => cd.ClientId == clientId)
            .OrderByDescending(cd => cd.Timestamp)
            .FirstOrDefault();

        if (clientData != null)
        {
            _cacheManager.Set(cacheKey, clientData, TimeSpan.FromMinutes(10));
        }

        return clientData;
    }
}

3. API接口

我们将使用ASP.NET Core来提供RESTful API接口。

3.1 安装ASP.NET Core

首先,安装ASP.NET Core的NuGet包:

dotnet add package Microsoft.AspNetCore.App
3.2 创建API控制器

Controllers/ClientDataController.cs:

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

[ApiController]
[Route("api/[controller]")]
public class ClientDataController : ControllerBase
{
    private DatabaseManager _databaseManager;

    public ClientDataController()
    {
        _databaseManager = new DatabaseManager();
    }

    [HttpGet("{clientId}")]
    public ActionResult<ClientData> GetClientData(int clientId)
    {
        var clientData = _databaseManager.GetClientData(clientId);
        if (clientData == null)
        {
            return NotFound();
        }
        return Ok(clientData);
    }

    [HttpPost]
    public ActionResult SaveClientData([FromBody] ClientData clientData)
    {
        _databaseManager.SaveClientData(clientData.ClientId, clientData.Data);
        return Ok();
    }
}
3.3 配置ASP.NET Core

Program.cs:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Startup.cs:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

总结

通过以上扩展和优化,我们进一步提高了系统的功能性和性能。数据库集成实现了数据的持久化和查询,缓存机制提高了系统性能,API接口便于外部系统集成。

你可以根据具体需求继续扩展和优化这个实现,例如添加更多的API接口、优化缓存策略、增强数据库操作等。希望这些示例和思路能对你有所帮助。

好的,我们可以继续扩展和优化系统。接下来,我们将添加以下功能:

  1. 身份验证和授权:确保只有授权用户可以访问API。
  2. 日志记录和监控:增强系统的可观测性和可维护性。
  3. 单元测试:确保系统的可靠性和稳定性。

1. 身份验证和授权

我们将使用JWT(JSON Web Token)来实现身份验证和授权。

1.1 安装JWT相关的NuGet包
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt
1.2 配置JWT

Startup.cs:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();

        var key = Encoding.ASCII.GetBytes("YourSecretKeyHere");
        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}
1.3 创建身份验证控制器

Controllers/AuthController.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    [HttpPost("login")]
    public IActionResult Login([FromBody] UserLogin userLogin)
    {
        // 这里应该验证用户的用户名和密码
        if (userLogin.Username == "test" && userLogin.Password == "password")
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes("YourSecretKeyHere");
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name, userLogin.Username)
                }),
                Expires = DateTime.UtcNow.AddHours(1),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            var tokenString = tokenHandler.WriteToken(token);

            return Ok(new { Token = tokenString });
        }

        return Unauthorized();
    }
}

public class UserLogin
{
    public string Username { get; set; }
    public string Password { get; set; }
}
1.4 保护API控制器

Controllers/ClientDataController.cs:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class ClientDataController : ControllerBase
{
    private DatabaseManager _databaseManager;

    public ClientDataController()
    {
        _databaseManager = new DatabaseManager();
    }

    [HttpGet("{clientId}")]
    public ActionResult<ClientData> GetClientData(int clientId)
    {
        var clientData = _databaseManager.GetClientData(clientId);
        if (clientData == null)
        {
            return NotFound();
        }
        return Ok(clientData);
    }

    [HttpPost]
    public ActionResult SaveClientData([FromBody] ClientData clientData)
    {
        _databaseManager.SaveClientData(clientData.ClientId, clientData.Data);
        return Ok();
    }
}

2. 日志记录和监控

我们将使用Serilog来增强系统的日志记录和监控。

2.1 安装Serilog相关的NuGet包
dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File
2.2 配置Serilog

Program.cs:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Serilog;

public class Program
{
    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day)
            .CreateLogger();

        try
        {
            Log.Information("Starting web host");
            CreateHostBuilder(args).Build().Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly");
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseSerilog()
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}
2.3 使用Serilog记录日志

Controllers/ClientDataController.cs:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Serilog;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class ClientDataController : ControllerBase
{
    private DatabaseManager _databaseManager;

    public ClientDataController()
    {
        _databaseManager = new DatabaseManager();
    }

    [HttpGet("{clientId}")]
    public ActionResult<ClientData> GetClientData(int clientId)
    {
        Log.Information($"Fetching data for client {clientId}");
        var clientData = _databaseManager.GetClientData(clientId);
        if (clientData == null)
        {
            Log.Warning($"No data found for client {clientId}");
            return NotFound();
        }
        return Ok(clientData);
    }

    [HttpPost]
    public ActionResult SaveClientData([FromBody] ClientData clientData)
    {
        Log.Information($"Saving data for client {clientData.ClientId}");
        _databaseManager.SaveClientData(clientData.ClientId, clientData.Data);
        return Ok();
    }
}

3. 单元测试

我们将使用xUnit和Moq来编写单元测试。

3.1 安装xUnit和Moq相关的NuGet包
dotnet add package xunit
dotnet add package Moq
dotnet add package Microsoft.AspNetCore.Mvc.Testing
3.2 创建单元测试项目

创建一个新的测试项目:

dotnet new xunit -n MyProject.Tests
3.3 编写单元测试

MyProject.Tests/ClientDataControllerTests.cs:

using Microsoft.AspNetCore.Mvc;
using Moq;
using Xunit;

public class ClientDataControllerTests
{
    private readonly Mock<DatabaseManager> _mockDatabaseManager;
    private readonly ClientDataController _controller;

    public ClientDataControllerTests()
    {
        _mockDatabaseManager = new Mock<DatabaseManager>();
        _controller = new ClientDataController(_mockDatabaseManager.Object);
    }

    [Fact]
    public void GetClientData_ReturnsOkResult_WhenDataExists()
    {
        // Arrange
        var clientId = 1;
        var clientData = new ClientData { ClientId = clientId, Data = new byte[] { 1, 2, 3 } };
        _mockDatabaseManager.Setup(dm => dm.GetClientData(clientId)).Returns(clientData);

        // Act
        var result = _controller.GetClientData(clientId);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result.Result);
        var returnValue = Assert.IsType<ClientData>(okResult.Value);
        Assert.Equal(clientId, returnValue.ClientId);
    }

    [Fact]
    public void GetClientData_ReturnsNotFoundResult_WhenDataDoesNotExist()
    {
        // Arrange
        var clientId = 1;
        _mockDatabaseManager.Setup(dm => dm.GetClientData(clientId)).Returns((ClientData)null);

        // Act
        var result = _controller.GetClientData(clientId);

        // Assert
        Assert.IsType<NotFoundResult>(result.Result);
    }
}

总结

通过以上扩展和优化,我们进一步增强了系统的安全性、可观测性和可靠性。身份验证和授权确保了只有授权用户可以访问API,日志记录和监控增强了系统的可观测性和可维护性,单元测试确保了系统的可靠性和稳定性。

你可以根据具体需求继续扩展和优化这个实现,例如添加更多的测试用例、优化日志记录策略、增强身份验证和授权机制等。希望这些示例和思路能对你有所帮助。

好的,我们可以继续扩展和优化系统。接下来,我们将添加以下功能:

  1. 错误处理和异常管理:确保系统能够优雅地处理和记录错误。
  2. 配置管理:使用配置文件和环境变量来管理应用程序配置。
  3. 性能优化:通过缓存和其他技术提高系统性能。

1. 错误处理和异常管理

我们将使用全局异常处理中间件来捕获和处理未处理的异常,并记录这些异常。

1.1 创建全局异常处理中间件

Middleware/ExceptionMiddleware.cs:

using Microsoft.AspNetCore.Http;
using Serilog;
using System;
using System.Net;
using System.Threading.Tasks;

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;

    public ExceptionMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (Exception ex)
        {
            Log.Error($"Something went wrong: {ex}");
            await HandleExceptionAsync(httpContext, ex);
        }
    }

    private Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        return context.Response.WriteAsync(new ErrorDetails()
        {
            StatusCode = context.Response.StatusCode,
            Message = "Internal Server Error from the custom middleware."
        }.ToString());
    }
}

public class ErrorDetails
{
    public int StatusCode { get; set; }
    public string Message { get; set; }

    public override string ToString()
    {
        return Newtonsoft.Json.JsonConvert.SerializeObject(this);
    }
}
1.2 注册中间件

Startup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
  • 17
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛掰是怎么形成的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值