TcpClient 一个TCP的收发类,支持长数据读写

internal class TcpCommunicator : IMessageCommunicator
{
    private TcpClient? _TcpClient;
    private NetworkStream? _NetworkStream;
    private CancellationTokenSource? _ReceiveCts;
    private readonly SemaphoreSlim _SendSemaphore = new(1, 1);
    private bool _IsDisposed = false;

    NetworkCommConfig _Config;
    public ICommConfig Config => _Config;
    public bool IsConnected => _TcpClient?.Connected ?? false;

    public event Func<bool, ValueTask>? ConnectStatusChanged;
    public event Func<ReadOnlyMemory<byte>, ValueTask>? OnDataReceived;

    public TcpCommunicator(NetworkCommConfig config)
    {
        _Config = config;
    }
    public TcpCommunicator(string ipv4, int port)
    {
        _Config = new NetworkCommConfig(ipv4, port);
    }



    public async ValueTask ConnectAsync(CancellationToken token = default)
    {
        if (_IsDisposed) throw new ObjectDisposedException(nameof(TcpCommunicator));
        if (IsConnected) return;

        await DisconnectAsync(token);
        try
        {
            var client = new TcpClient();

            await client.ConnectAsync(_Config.Ipv4, _Config.Port).ConfigureAwait(false);
            _TcpClient = client;
            _NetworkStream = client.GetStream();
            _ReceiveCts = new CancellationTokenSource();

            ReceiveLoop();
        }
        catch
        {
            await DisconnectAsync(token);
        }

        if (IsConnected)
            ConnectStatusChanged?.Invoke(true);
    }

    public async ValueTask DisconnectAsync(CancellationToken token = default)
    {
        if (_ReceiveCts is not null)
        {
            await _ReceiveCts.CancelAsync();
            _ReceiveCts.Dispose();
            _ReceiveCts = null;
        }

        _NetworkStream?.Dispose();
        _NetworkStream = null;

        _TcpClient?.Dispose();
        _TcpClient = null;
    }

    public async ValueTask DisposeAsync()
    {
        if (_IsDisposed) return;
        _IsDisposed = true;
        await DisconnectAsync();
        _SendSemaphore.Dispose();
        GC.SuppressFinalize(this);
    }


    MemoryStream _ReceiveStream = new();
    /// <summary>
    /// 发送回调
    /// </summary>
    /// <param name="dataReceived"></param>
    /// <returns></returns>
    async ValueTask SendReceive(ReadOnlyMemory<byte> dataReceived)
    {
        await _ReceiveStream.WriteAsync(dataReceived);
    }
    Stopwatch _CilentStopwatch = new();
    public async ValueTask<ReadOnlyMemory<byte>> Send(ReadOnlyMemory<byte> data, CancellationToken token = default)
    {
        if (!IsConnected) throw new InvalidOperationException("Not connected");

        await _SendSemaphore.WaitAsync(token);
        CancellationTokenSource _timeoutCTS = CancellationTokenSource.CreateLinkedTokenSource(token
            , new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);

        try
        {
            _ReceiveStream.SetLength(0);
            OnDataReceived += SendReceive;
            await SendAsync(data, token);
            long receiveLength = 0;
            while (!_timeoutCTS.Token.IsCancellationRequested)
            {
                await Task.Delay(50, _timeoutCTS.Token);
                if (_ReceiveStream.Length == 0) continue;
                if (receiveLength != _ReceiveStream.Length) // 数据长度变化,重置计时器
                {
                    receiveLength = _ReceiveStream.Length;
                    _CilentStopwatch.Restart();
                }
                else if (_CilentStopwatch.ElapsedMilliseconds > 260) // 超过260 ms 数据无变化,认为接收完成
                {
                    break;
                }
            }
            return _ReceiveStream.ToArray();
        }
        catch (OperationCanceledException)
        {
            // 超时
            return ReadOnlyMemory<byte>.Empty;
        }
        finally
        {
            OnDataReceived -= SendReceive;
            _SendSemaphore.Release();
        }
    }

    public ValueTask SendAsync(ReadOnlyMemory<byte> data, CancellationToken token = default) => _NetworkStream!.WriteAsync(data.ToArray(), token);


    #region  接收循环(高性能 Memory 版

    bool _IsLooping = false;
    Lock loopLocker = new Lock();
    private void ReceiveLoop()
    {
        lock (loopLocker)
        {
            if (_IsLooping) return;
            _IsLooping = true;
        }
        Task.Run(async () =>
        {
            // 用 Memory<byte> 定义缓冲区(零拷贝)
            Memory<byte> buffer = new byte[1024 * 10];

            try
            {
                while (!_ReceiveCts!.IsCancellationRequested)
                {
                    // 直接 ReadAsync into Memory
                    int n = await _NetworkStream!
                        .ReadAsync(buffer, _ReceiveCts.Token)
                        .ConfigureAwait(false);

                    if (n == 0)
                        break;

                    // 切片:零拷贝,不分配新数组
                    var dataMemory = buffer.Slice(0, n);
                    // ✅ 直接抛 Memory 给事件,不拷贝!
                    OnDataReceived?.Invoke(dataMemory);
                }
            }
            catch (OperationCanceledException) { }
            catch (Exception ex)
            {
                // 可在这里触发错误事件
                // OnError?.Invoke(ex);
                throw;
            }
            finally
            {
                await DisconnectAsync(_ReceiveCts!.Token);
            }
        }).ContinueWith(t =>
        {
            _IsLooping = false;
            ConnectStatusChanged?.Invoke(false);
        });
    }

    #endregion
}

 

posted @ 2025-03-06 18:19  cchong005  阅读(24)  评论(0)    收藏  举报