HP-Socket压力测试例子,用恐怖如斯来形容。

‌HP-Socket‌是一套开源通用的‌高性能TCP/UDP/HTTP通信框架‌,由JessMA Open Source开发维护,支持多语言、跨平台,广泛应用于高并发网络通信场景开发。

一、核心工作原理

HP-Socket采用分层架构设计,基于平台最优的事件驱动模型,结合内存管理优化技术实现高性能通信:

  1. ‌分层架构‌:从底层到高层分为平台适配层、IO处理层、通信框架层、应用协议层,完整封装底层通信细节,与应用层完全解耦
  2. ‌平台适配模型‌:
    • Server/Agent组件:Windows基于‌IOCP‌模型,Linux基于‌EPOLL‌模型,匹配平台原生高性能IO特性
    • Client组件:基于Event Select/POLL模型,每个组件管理单个Socket连接,适用于小规模客户端场景
  3. ‌核心优化机制‌:
    • 使用‌内存池+私有堆‌技术,减少内存分配开销和内存碎片,实现高效内存管理
    • 支持PUSH/PULL/PACK三种接收模型,其中PACK模型可自动处理分包粘包,降低应用层处理复杂度
    • 基于事件通知模型,通过回调函数处理连接建立、数据接收、连接关闭等网络事件,避免线程阻塞
  4. ‌标准工作流程‌:创建监听器→创建并绑定通信组件→启动组件→处理通信事件→停止组件→销毁组件

二、核心优势

1. 通用性与解耦设计

HP-Socket仅负责字节流的收发,不参与应用层协议解析,和应用程序通过接口交互且完全解耦,任何实现接口规范的应用都可以无缝整合。

2. 优异的易用性

  • 接口设计简单统一,完全封装底层通信细节,应用无需干预底层操作
  • 提供PUSH/PULL/PACK多种接收模型,可灵活选择封解包处理方式,降低出错概率
  • 提供完整的示例代码(性能测试、多语言演示),开箱即用降低开发门槛。

3. 良好的伸缩性

应用可根据实际场景(容量需求、通信规模、资源状况)调整性能参数:包括工作线程数量、缓存池大小、收发模式等,优化资源配置,避免资源浪费。

4. 完善的功能支持

  • 全协议覆盖:支持TCP/UDP/HTTP/HTTPS/WebSocket,UDP模式还提供可选ARQ可靠传输机制
  • 跨平台兼容:原生支持Windows/Linux,v5.8+版本支持macOS和Android移动端
  • 多语言接口:原生支持C/C++,扩展支持C#、Python、Java、Delphi、易语言等多种开发语言
  • 企业级特性:支持数十万级并发连接,内置流量整形、监控统计、自动重连容错机制

上压测源码:

效果:

1111111

单机i7办公电脑居然能跑出接近50wQps的速度。

服务端  HPSocketTest.Server.exe源码:

using HPSocket;
using HPSocket.Tcp;
using HPSocketTest.Common;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace HPSocketTest.Server;

class Program
{
    // 响应缓冲区池,减少 GC
    private static readonly ConcurrentBag<byte[]> ResponsePool = new();

    static async Task Main(string[] args)
    {
        Console.Title = "HPSocket TCP PACK Server - 压力测试服务端";
        Console.WriteLine("╔══════════════════════════════════════════════════════════════╗");
        Console.WriteLine("║     HPSocket.Net TCP PACK Server - 高性能压力测试服务端       ║");
        Console.WriteLine("╚══════════════════════════════════════════════════════════════╝");

        var cts = new CancellationTokenSource();
        Console.CancelKeyPress += (s, e) => { e.Cancel = true; cts.Cancel(); };

        // 配置参数
        ushort port = args.Length > 0 && ushort.TryParse(args[0], out var p) ? p : (ushort)5555;
        int workerThreads = args.Length > 1 && int.TryParse(args[1], out var w) ? w : Environment.ProcessorCount * 2;

        // 初始化响应池
        for (int i = 0; i < 200; i++)
            ResponsePool.Add(new byte[8192]);

        // 创建 PACK 服务端(非泛型)
        var server = new TcpPackServer()
        {
            // PACK 模型关键配置
            PackHeaderFlag = 0x00,                    // 包头标志(不使用特殊标志)
            //PackHeaderSize = PacketHeader.HeaderSize, // 包头大小 16 字节
            MaxPackSize = 65535,                      // 最大包大小

            // 性能调优
            SocketBufferSize = 65536,
            SocketListenQueue = 500,
            WorkerThreadCount = (uint)workerThreads,

            // 心跳检测
            KeepAliveTime = 60000,
            KeepAliveInterval = 10000,
            Address="0.0.0.0",
            Port=port,
        };

        var stats = new PerformanceStatistics();
        var sw = Stopwatch.StartNew();
        var clientInfo = new ConcurrentDictionary<IntPtr, ClientContext>();

        // ===== 事件绑定 =====

        server.OnPrepareListen += (sender, soListen) =>
        {
            Console.WriteLine($"[准备监听] Socket: {soListen}, 工作线程: {workerThreads}");
            return HandleResult.Ok;
        };

        server.OnAccept += (sender, connId, client) =>
        {
            stats.IncrementConnections();
            string ip2; ushort port2;
            sender.GetRemoteAddress(connId, out ip2, out port2);
            var ctx = new ClientContext
            {
                ConnId = connId,
                ConnectTime = DateTime.Now,
                RemoteAddress = $"{ip2}:{port2}"
            };
            clientInfo[connId] = ctx;
            Console.WriteLine($"[连接建立] {ctx.RemoteAddress} (总连接: {stats.ActiveConnections})");
            return HandleResult.Ok;
        };

        // OnReceive 收到的是完整数据包(不含包头),即只有包体
        // 但我们在包头中放了命令信息,所以需要自己解析包头
        // 实际上 PACK 模型的 OnReceive 参数 data 是【完整包数据(含包头)】
        server.OnReceive += (sender, connId, data) =>
        {
            try
            {
                stats.AddBytesReceived(data.Length);

                // PACK 模型下,data 是完整的数据包(含包头)
                if (data.Length < PacketHeader.HeaderSize)
                {
                    stats.IncrementErrors();
                    return HandleResult.Error;
                }

                // 解析包头
                var header = MemoryMarshal.Read<PacketHeader>(data.AsSpan());
                if (!header.IsValid)
                {
                    stats.IncrementErrors();
                    return HandleResult.Error;
                }

                stats.IncrementMessagesReceived();

                // 根据命令处理
                switch ((CommandType)header.Command)
                {
                    case CommandType.EchoRequest:
                        return HandleEcho(server, connId, header, data, stats);

                    case CommandType.BenchmarkRequest:
                        return HandleBenchmark(server, connId, header, data, stats);

                    case CommandType.Heartbeat:
                        return HandleHeartbeat(server, connId, header);

                    default:
                        return HandleResult.Ok;
                }
            }
            catch (Exception ex)
            {
                stats.IncrementErrors();
                Console.WriteLine($"[处理异常] {ex.Message}");
                return HandleResult.Error;
            }
        };

        server.OnClose += (sender, connId, socketOperation, errorCode) =>
        {
            stats.DecrementConnections();
            if (clientInfo.TryRemove(connId, out var ctx))
            {
                var duration = DateTime.Now - ctx.ConnectTime;
                Console.WriteLine($"[连接关闭] {ctx.RemoteAddress}, 存活: {duration.TotalSeconds:F1}s, 错误码: {errorCode}");
            }
            return HandleResult.Ok;
        };

        server.OnShutdown += (sender) =>
        {
            Console.WriteLine("[服务关闭]");
            return HandleResult.Ok;
        };

        // 启动服务
        if (!server.Start())
        {
            Console.WriteLine($"[启动失败] {server.ErrorMessage}");
            return;
        }

        Console.WriteLine($"[服务启动] 监听端口: {port}, PID: {Environment.ProcessId}");
        Console.WriteLine("按 Ctrl+C 停止服务...\n");

        // 统计输出任务
        _ = Task.Run(async () =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                await Task.Delay(5000, cts.Token);
                var elapsed = sw.Elapsed.TotalSeconds;
                var qps = elapsed > 0 ? stats.TotalMessagesReceived / elapsed : 0;
                var throughput = elapsed > 0 ? (stats.TotalBytesSent + stats.TotalBytesReceived) / elapsed / 1024 / 1024 : 0;

                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] QPS: {qps:N0}/s | 吞吐: {throughput:F2} MB/s | {stats}");
            }
        }, cts.Token);

        try { await Task.Delay(-1, cts.Token); } catch { }

        Console.WriteLine("\n[正在停止...]");
        server.Stop();
        Console.WriteLine($"[运行统计] 总时长: {sw.Elapsed}, {stats}");
    }

    static HandleResult HandleEcho(ITcpPackServer server, IntPtr connId,
        PacketHeader header, byte[] data, PerformanceStatistics stats)
    {
        if (!ResponsePool.TryTake(out var buffer))
            buffer = new byte[data.Length];

        try
        {
            data.AsSpan().CopyTo(buffer);

            var respHeader = PacketHeader.Create(
                (ushort)CommandType.EchoResponse,
                header.BodyLength,
                header.Sequence);

            MemoryMarshal.Write(buffer.AsSpan(), ref respHeader);

            if (server.Send(connId, buffer, 0, PacketHeader.HeaderSize + (int)header.BodyLength))
            {
                stats.IncrementMessagesSent();
                stats.AddBytesSent(PacketHeader.HeaderSize + header.BodyLength);
                return HandleResult.Ok;
            }
            return HandleResult.Error;
        }
        finally
        {
            ResponsePool.Add(buffer);
        }
    }

    static HandleResult HandleBenchmark(ITcpPackServer server, IntPtr connId,
        PacketHeader header, byte[] data, PerformanceStatistics stats)
    {
        if (!ResponsePool.TryTake(out var buffer))
            buffer = new byte[data.Length];

        try
        {
            data.AsSpan().CopyTo(buffer);

            var respHeader = PacketHeader.Create(
                (ushort)CommandType.BenchmarkResponse,
                header.BodyLength,
                header.Sequence);

            MemoryMarshal.Write(buffer.AsSpan(), ref respHeader);

            if (server.Send(connId, buffer, 0, PacketHeader.HeaderSize + (int)header.BodyLength))
            {
                stats.IncrementMessagesSent();
                stats.AddBytesSent(PacketHeader.HeaderSize + header.BodyLength);
                return HandleResult.Ok;
            }
            return HandleResult.Error;
        }
        finally
        {
            ResponsePool.Add(buffer);
        }
    }

    static HandleResult HandleHeartbeat(ITcpPackServer server, IntPtr connId, PacketHeader header)
    {
        if (!ResponsePool.TryTake(out var buffer))
            buffer = new byte[PacketHeader.HeaderSize];

        try
        {
            var resp = PacketHeader.Create((ushort)CommandType.Heartbeat, 0, header.Sequence);
            MemoryMarshal.Write(buffer.AsSpan(), ref resp);

            server.Send(connId, buffer, 0, PacketHeader.HeaderSize);
            return HandleResult.Ok;
        }
        finally
        {
            ResponsePool.Add(buffer);
        }
    }
}

public class ClientContext
{
    public IntPtr ConnId { get; set; }
    public DateTime ConnectTime { get; set; }
    public string RemoteAddress { get; set; } = "";
}

 

客户端  HPSocketTest.Client.exe源码:

using HPSocket;
using HPSocket.Tcp;
using HPSocketTest.Common;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace HPSocketTest.Client;

class Program
{
    static async Task Main(string[] args)
    {
        Console.Title = "HPSocket TCP PACK Client - 压力测试客户端";
        Console.WriteLine("╔══════════════════════════════════════════════════════════════╗");
        Console.WriteLine("║     HPSocket.Net TCP PACK Client - 并发压力测试客户端         ║");
        Console.WriteLine("╚══════════════════════════════════════════════════════════════╝");

        // 解析参数
        var config = ParseArgs(args);
        Console.WriteLine($"[配置] 服务器: {config.Host}:{config.Port}");
        Console.WriteLine($"[配置] 并发连接: {config.Connections}");
        Console.WriteLine($"[配置] 消息大小: {config.MessageSize} bytes, 持续时间: {config.DurationSeconds}s");
        Console.WriteLine($"[配置] 发送间隔: {config.SendIntervalMs}ms, 批量发送: {config.BatchSize}");
        Console.WriteLine();

        var cts = new CancellationTokenSource();
        Console.CancelKeyPress += (s, e) => { e.Cancel = true; cts.Cancel(); };

        // 全局统计
        var globalStats = new PerformanceStatistics();
        var latencyHistogram = new ConcurrentBag<double>();
        var sw = Stopwatch.StartNew();

        // 创建连接池
        var clients = new List<BenchmarkClient>();
        var connectionTasks = new List<Task>();

        Console.WriteLine("[阶段1] 建立连接中...");
        for (int i = 0; i < config.Connections; i++)
        {
            var client = new BenchmarkClient(config, globalStats, latencyHistogram);
            clients.Add(client);

            int connIndex = i;
            connectionTasks.Add(Task.Run(async () =>
            {
                if (await client.ConnectAsync())
                {
                    if ((connIndex + 1) % 100 == 0 || connIndex == 0)
                        Console.WriteLine($"  已建立 {connIndex + 1}/{config.Connections} 连接...");
                }
            }));

            // 控制连接建立速率
            if (i % 50 == 0) await Task.Delay(10);
        }

        await Task.WhenAll(connectionTasks);
        var connectedCount = clients.Count(c => c.IsConnected);
        Console.WriteLine($"[阶段1完成] 成功连接: {connectedCount}/{config.Connections}");

        if (connectedCount == 0)
        {
            Console.WriteLine("[错误] 没有成功建立的连接,退出");
            return;
        }

        Console.WriteLine("[阶段2] 开始压力测试...");
        var testTasks = clients
            .Where(c => c.IsConnected)
            .Select(c => c.RunBenchmarkAsync(cts.Token))
            .ToArray();

        // 监控任务
        var monitorTask = Task.Run(async () =>
        {
            var lastSent = 0L;
            var lastRecv = 0L;
            var lastTime = sw.Elapsed;

            while (!cts.Token.IsCancellationRequested)
            {
                await Task.Delay(1000, cts.Token);
                var now = sw.Elapsed;
                var elapsed = (now - lastTime).TotalSeconds;

                var currentSent = globalStats.TotalMessagesSent;
                var currentRecv = globalStats.TotalMessagesReceived;
                var qpsSend = (currentSent - lastSent) / elapsed;
                var qpsRecv = (currentRecv - lastRecv) / elapsed;

                // 计算延迟统计
                var latencies = latencyHistogram.ToArray();
                var avgLatency = latencies.Length > 0 ? latencies.Average() : 0;
                var p99Latency = latencies.Length > 0 ?
                    latencies.OrderBy(x => x).Skip((int)(latencies.Length * 0.99)).FirstOrDefault() : 0;

                Console.WriteLine($"[{now:hh\\:mm\\:ss}] " +
                    $"发送QPS: {qpsSend:N0}/s | 接收QPS: {qpsRecv:N0}/s | " +
                    $"平均延迟: {avgLatency:F2}ms | P99延迟: {p99Latency:F2}ms | " +
                    $"活跃连接: {globalStats.ActiveConnections}");

                lastSent = currentSent;
                lastRecv = currentRecv;
                lastTime = now;

                // 清理旧采样
                while (latencyHistogram.Count > 100000)
                    latencyHistogram.TryTake(out _);
            }
        }, cts.Token);

        // 定时结束
        if (config.DurationSeconds > 0)
        {
            _ = Task.Run(async () =>
            {
                await Task.Delay(config.DurationSeconds * 1000);
                Console.WriteLine($"\n[时间到] 测试持续 {config.DurationSeconds}s,正在停止...");
                cts.Cancel();
            });
        }

        try
        {
            await Task.WhenAll(testTasks);
        }
        catch (OperationCanceledException) { }

        sw.Stop();

        // 输出最终报告
        PrintFinalReport(sw, config, clients, globalStats, latencyHistogram);

        // 断开所有连接
        Console.WriteLine("\n[清理] 断开连接...");
        await Task.WhenAll(clients.Select(c => c.DisconnectAsync()));
        Console.WriteLine("[完成]");
    }

    static void PrintFinalReport(Stopwatch sw, BenchmarkConfig config,
        List<BenchmarkClient> clients, PerformanceStatistics stats, ConcurrentBag<double> latencyHistogram)
    {
        Console.WriteLine("\n╔══════════════════════════════════════════════════════════════╗");
        Console.WriteLine("║                      压力测试最终报告                         ║");
        Console.WriteLine("╚══════════════════════════════════════════════════════════════╝");

        var totalSeconds = sw.Elapsed.TotalSeconds;
        var finalLatencies = latencyHistogram.ToArray();

        Console.WriteLine($"运行时长: {sw.Elapsed:hh\\:mm\\:ss\\.fff}");
        Console.WriteLine($"总连接数: {config.Connections} (成功: {clients.Count(c => c.IsConnected)})");
        Console.WriteLine($"总发送消息: {stats.TotalMessagesSent:N0}");
        Console.WriteLine($"总接收消息: {stats.TotalMessagesReceived:N0}");
        Console.WriteLine($"平均发送QPS: {stats.TotalMessagesSent / totalSeconds:N0}/s");
        Console.WriteLine($"平均接收QPS: {stats.TotalMessagesReceived / totalSeconds:N0}/s");
        Console.WriteLine($"总发送数据: {stats.TotalBytesSent:N0} bytes ({stats.TotalBytesSent / 1024.0 / 1024:F2} MB)");
        Console.WriteLine($"总接收数据: {stats.TotalBytesReceived:N0} bytes ({stats.TotalBytesReceived / 1024.0 / 1024:F2} MB)");
        Console.WriteLine($"平均吞吐: {(stats.TotalBytesSent + stats.TotalBytesReceived) / totalSeconds / 1024.0 / 1024:F2} MB/s");
        Console.WriteLine($"总错误数: {stats.TotalErrors}");

        if (finalLatencies.Length > 0)
        {
            Array.Sort(finalLatencies);
            Console.WriteLine($"\n--- 延迟统计 (样本: {finalLatencies.Length}) ---");
            Console.WriteLine($"最小延迟: {finalLatencies[0]:F3}ms");
            Console.WriteLine($"平均延迟: {finalLatencies.Average():F3}ms");
            Console.WriteLine($"P50延迟: {finalLatencies[finalLatencies.Length / 2]:F3}ms");
            Console.WriteLine($"P90延迟: {finalLatencies[(int)(finalLatencies.Length * 0.90)]:F3}ms");
            Console.WriteLine($"P99延迟: {finalLatencies[(int)(finalLatencies.Length * 0.99)]:F3}ms");
            Console.WriteLine($"P999延迟: {finalLatencies[(int)(finalLatencies.Length * 0.999)]:F3}ms");
            Console.WriteLine($"最大延迟: {finalLatencies[^1]:F3}ms");
        }
    }

    static BenchmarkConfig ParseArgs(string[] args)
    {
        var config = new BenchmarkConfig();

        for (int i = 0; i < args.Length; i += 2)
        {
            if (i + 1 >= args.Length) break;
            var key = args[i].ToLower();
            var value = args[i + 1];

            switch (key)
            {
                case "-h": case "--host": config.Host = value; break;
                case "-p": case "--port": config.Port = ushort.Parse(value); break;
                case "-c": case "--connections": config.Connections = int.Parse(value); break;
                case "-s": case "--size": config.MessageSize = int.Parse(value); break;
                case "-d": case "--duration": config.DurationSeconds = int.Parse(value); break;
                case "-i": case "--interval": config.SendIntervalMs = int.Parse(value); break;
                case "-b": case "--batch": config.BatchSize = int.Parse(value); break;
            }
        }

        return config;
    }
}

public class BenchmarkConfig
{
    public string Host { get; set; } = "127.0.0.1";
    public ushort Port { get; set; } = 5555;
    public int Connections { get; set; } = 1000;
    public int MessageSize { get; set; } = 256;
    public int DurationSeconds { get; set; } = 30;
    public int SendIntervalMs { get; set; } = 0;
    public int BatchSize { get; set; } = 1;
}

public class BenchmarkClient
{
    private readonly BenchmarkConfig _config;
    private readonly PerformanceStatistics _globalStats;
    private readonly ConcurrentBag<double> _latencyHistogram;
    private TcpPackClient? _client;
    private readonly ConcurrentDictionary<uint, Stopwatch> _pendingRequests;
    private uint _sequence;
    private byte[]? _sendBuffer;

    public bool IsConnected { get; private set; }

    public BenchmarkClient(BenchmarkConfig config, PerformanceStatistics stats, ConcurrentBag<double> latency)
    {
        _config = config;
        _globalStats = stats;
        _latencyHistogram = latency;
        _pendingRequests = new ConcurrentDictionary<uint, Stopwatch>();
    }

    public async Task<bool> ConnectAsync()
    {
        // 创建 PACK 客户端(非泛型)
        _client = new TcpPackClient()
        {
            PackHeaderFlag = 0x00,
            //PackHeaderSize = PacketHeader.HeaderSize,
            MaxPackSize = 65535,
            SocketBufferSize = 65536,
        };

        // 准备发送缓冲区
        _sendBuffer = new byte[PacketHeader.HeaderSize + _config.MessageSize];
        var header = PacketHeader.Create((ushort)CommandType.BenchmarkRequest, (uint)_config.MessageSize, 0);
        MemoryMarshal.Write(_sendBuffer.AsSpan(), ref header);
        new Random().NextBytes(_sendBuffer.AsSpan(PacketHeader.HeaderSize));

        var connectTcs = new TaskCompletionSource<bool>();
        _client.OnConnect += (sender) =>
        {
            IsConnected = true;
            _globalStats.IncrementConnections();
            connectTcs.TrySetResult(true);
            return HandleResult.Ok;
        };

        _client.OnReceive += (sender, data) =>
        {
            try
            {
                _globalStats.AddBytesReceived(data.Length);

                if (data.Length >= PacketHeader.HeaderSize)
                {
                    var respHeader = MemoryMarshal.Read<PacketHeader>(data.AsSpan());

                    if (_pendingRequests.TryRemove(respHeader.Sequence, out var timer))
                    {
                        _latencyHistogram.Add(timer.Elapsed.TotalMilliseconds);
                    }

                    _globalStats.IncrementMessagesReceived();
                }
                return HandleResult.Ok;
            }
            catch
            {
                _globalStats.IncrementErrors();
                return HandleResult.Error;
            }
        };

        _client.OnClose += (sender, operation, errorCode) =>
        {
            IsConnected = false;
            _globalStats.DecrementConnections();
            connectTcs.TrySetResult(false);
            return HandleResult.Ok;
        };

        // 启动并连接
        if (!_client.Connect(_config.Host, _config.Port))
        {
            return false;
        }

        // 等待连接结果或超时
        var completed = await Task.WhenAny(connectTcs.Task, Task.Delay(5000));
        if (completed != connectTcs.Task)
        {
            _client.Stop();
            return false;
        }

        return connectTcs.Task.Result;
    }

    

    public async Task RunBenchmarkAsync(CancellationToken ct)
    {
        if (_client == null || _sendBuffer == null) return;

        var buffer = new byte[_sendBuffer.Length];
        _sendBuffer.CopyTo(buffer, 0);

        while (!ct.IsCancellationRequested && IsConnected)
        {
            try
            {
                for (int b = 0; b < _config.BatchSize; b++)
                {
                    var seq = Interlocked.Increment(ref _sequence);

                    // 更新序列号
                    var header = PacketHeader.Create(
                        (ushort)CommandType.BenchmarkRequest,
                        (uint)_config.MessageSize,
                        seq);
                    MemoryMarshal.Write(buffer.AsSpan(), ref header);

                    // 记录发送时间
                    var timer = new Stopwatch();
                    timer.Start();
                    _pendingRequests[seq] = timer;

                    if (_client.Send(buffer, 0, buffer.Length))
                    {
                        _globalStats.IncrementMessagesSent();
                        _globalStats.AddBytesSent(buffer.Length);
                    }
                    else
                    {
                        _globalStats.IncrementErrors();
                        _pendingRequests.TryRemove(seq, out _);
                    }
                }

                // 控制发送速率
                if (_config.SendIntervalMs > 0)
                {
                    await Task.Delay(_config.SendIntervalMs, ct);
                }
                else
                {
                    // 全速发送时让出时间片
                    if (_sequence % 1000 == 0)
                        await Task.Yield();
                }
            }
            catch (OperationCanceledException)
            {
                break;
            }
            catch (Exception ex)
            {
                _globalStats.IncrementErrors();
                await Task.Delay(100, ct);
            }
        }
    }

    public Task DisconnectAsync()
    {
        IsConnected = false;
        _client?.Stop();
        return Task.CompletedTask;
    }
}

 

公用类库  HPSocketTest.Common.dll源码:

// ==================== Common/PacketHeader.cs ====================
using System.Runtime.InteropServices;

namespace HPSocketTest.Common;

/// <summary>
/// 包头结构 (16字节) - PACK 模型自动处理粘包
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PacketHeader
{
    public uint Magic;      // 魔数 0x48505343 (HPSC)
    public ushort Version;  // 协议版本
    public ushort Command;  // 命令类型
    public uint BodyLength; // 包体长度
    public uint Sequence;   // 序列号

    public const uint MagicValue = 0x48505343;
    public const int HeaderSize = 16;

    public static PacketHeader Create(ushort command, uint bodyLength, uint sequence)
    {
        return new PacketHeader
        {
            Magic = MagicValue,
            Version = 1,
            Command = command,
            BodyLength = bodyLength,
            Sequence = sequence
        };
    }

    public bool IsValid => Magic == MagicValue;
}

/// <summary>
/// 命令类型
/// </summary>
public enum CommandType : ushort
{
    Heartbeat = 0x0001,
    EchoRequest = 0x0010,
    EchoResponse = 0x0011,
    BenchmarkRequest = 0x0020,
    BenchmarkResponse = 0x0021,
    Error = 0x00FF
}


// ==================== Common/Statistics.cs ====================
namespace HPSocketTest.Common;

public class PerformanceStatistics
{
    private long _totalBytesSent;
    private long _totalBytesReceived;
    private long _totalMessagesSent;
    private long _totalMessagesReceived;
    private long _totalErrors;
    private long _activeConnections;

    public long TotalBytesSent => Interlocked.Read(ref _totalBytesSent);
    public long TotalBytesReceived => Interlocked.Read(ref _totalBytesReceived);
    public long TotalMessagesSent => Interlocked.Read(ref _totalMessagesSent);
    public long TotalMessagesReceived => Interlocked.Read(ref _totalMessagesReceived);
    public long TotalErrors => Interlocked.Read(ref _totalErrors);
    public long ActiveConnections => Interlocked.Read(ref _activeConnections);

    public void AddBytesSent(long bytes) => Interlocked.Add(ref _totalBytesSent, bytes);
    public void AddBytesReceived(long bytes) => Interlocked.Add(ref _totalBytesReceived, bytes);
    public void IncrementMessagesSent() => Interlocked.Increment(ref _totalMessagesSent);
    public void IncrementMessagesReceived() => Interlocked.Increment(ref _totalMessagesReceived);
    public void IncrementErrors() => Interlocked.Increment(ref _totalErrors);
    public void IncrementConnections() => Interlocked.Increment(ref _activeConnections);
    public void DecrementConnections() => Interlocked.Decrement(ref _activeConnections);

    public double GetThroughputMbps()
    {
        return (TotalBytesSent + TotalBytesReceived) * 8.0 / 1024 / 1024;
    }

    public override string ToString()
    {
        return $"[连接数: {ActiveConnections}] [发送: {TotalMessagesSent:N0} msg / {TotalBytesSent:N0} bytes] " +
               $"[接收: {TotalMessagesReceived:N0} msg / {TotalBytesReceived:N0} bytes] " +
               $"[错误: {TotalErrors}]";
    }
}

本例子采用的是PACK模型可自动处理分包粘包。以前繁琐的粘包问题从底层就直接解决了,虽然底层损失了些微性能,但比起java中的Netty框架依然还是强很多。

 

posted @ 2026-06-11 09:22  小y  阅读(5)  评论(0)    收藏  举报