public void Run(uint conv, IKcpCallback kcpCallback) { _recvFromRemote = new BufferBlock <DataPackage>(); _recvFromLocal = new BufferBlock <DataPackage>(); Conv = conv; _kcp = new Kcp(conv, kcpCallback, KcpRentable.Instacne); _kcp.NoDelay(1, 10, 2, 1); // 极速模式 _kcp.WndSize(128, 128); _kcp.SetMtu(MTU); _tokenSource = new CancellationTokenSource(); // 这样写的目的,在服务器上,压解缩、加解密可以利用多核(多个KCP连接之间的压解缩、加解密是可以并行的) // update Task.Factory.StartNew(async() => { // 检测并Flush数据到远端 while (!_tokenSource.IsCancellationRequested) { try { _kcp.Update(DateTime.UtcNow); await _kcp.CheckAwait(DateTime.UtcNow, _tokenSource.Token); } catch (TaskCanceledException) { break; } catch (ObjectDisposedException e) { // 一般情况下,OutPut时使用Socket发送数据时,而Socket被关闭时会进入此分支;暂时这么处理 if (e.ObjectName == "System.Net.Sockets.Socket") { break; } Debug.LogErrorFormat("Kcp.updateTask: \r\n {0}", e); } } }, _tokenSource.Token); // input from lower level Task.Factory.StartNew(async() => { // 收到 Ack 帧,需要移除 snd_buf;收到数据帧,则需要 Flush Ack while (!_tokenSource.IsCancellationRequested) { DataPackage package = null; try { package = await _recvFromRemote.ReceiveAsync(_tokenSource.Token); var result = _kcp.Input(package.MemoryOwner.Memory.Span.Slice(package.Offset, package.Lenght)); while (result == 0) { var(memoryOwner, avalidLength) = _kcp.TryRecv(); if (memoryOwner == null) { break; } // 在此解压、解密 OnRecvKcpPackage?.Invoke(memoryOwner, avalidLength, this); } ; } catch (TaskCanceledException) { _recvFromRemote.Complete(); break; } catch (Exception e) { Debug.LogErrorFormat("Kcp.inputTask: \r\n {0}", e); } finally { if (package != null) { package.MemoryOwner.Dispose(); DataPackage.Pool.Return(package); } } } }, _tokenSource.Token); // send by user Task.Factory.StartNew(async() => { // 有可能需要发送帧,需要Flush Snd_Queue while (!_tokenSource.IsCancellationRequested) { DataPackage package = null; try { package = await _recvFromLocal.ReceiveAsync(_tokenSource.Token); // 在此压缩、加密 _kcp.Send(package.MemoryOwner.Memory.Span.Slice(0, package.Lenght)); } catch (TaskCanceledException) { _recvFromLocal.Complete(); break; } catch (Exception e) { Debug.LogErrorFormat("Kcp.sendTask: \r\n {0}", e); } finally { if (package != null) { package.MemoryOwner.Dispose(); DataPackage.Pool.Return(package); } } } }, _tokenSource.Token); }