private async Task SendHelperAsync(Guid destination, MessageDto message, bool reliable) { var packetDto = PacketDto.Create(identity.Id, destination, message, reliable); var ms = outboundPacketMemoryStreamPool.TakeObject(); ms.SetLength(0); try { await AsyncSerialize.ToAsync(ms, packetDto).ConfigureAwait(false); } catch (NotSupportedException) { // surpassed memory stream buffer size. if (!reliable) { throw new InvalidOperationException("Attempted to send nonreliable buffer surpassing transport buffer size"); } ms.SetLength(0); outboundPacketMemoryStreamPool.ReturnObject(ms); await SendReliableMultipartPacketAsync(destination, packetDto).ConfigureAwait(false); #if DEBUG Interlocked.Increment(ref DebugRuntimeStats.out_rs_done); #endif return; } if (reliable) { var completionSignal = new AsyncLatch(); var acknowlewdgementSignal = acknowledgementCoordinator.Expect(packetDto.Id); unhandledSendRequestQueue.Enqueue( new SendRequest { DataBufferPool = outboundPacketMemoryStreamPool, Data = ms, DataOffset = 0, DataLength = (int)ms.Position, IsReliable = true, AcknowledgementSignal = acknowlewdgementSignal, AcknowledgementGuid = packetDto.Id, CompletionSignal = completionSignal }); workSignal.Set(); await completionSignal.WaitAsync().ConfigureAwait(false); } else { unhandledSendRequestQueue.Enqueue( new SendRequest { DataBufferPool = outboundPacketMemoryStreamPool, Data = ms, DataOffset = 0, DataLength = (int)ms.Position, IsReliable = false }); workSignal.Set(); } }
public async Task SendAcknowledgementAsync(Guid destination, AcknowledgementDto acknowledgement) { var ms = outboundAcknowledgementMemoryStreamPool.TakeObject(); ms.SetLength(0); await AsyncSerialize.ToAsync(ms, acknowledgement).ConfigureAwait(false); unhandledSendRequestQueue.Enqueue( new SendRequest { Data = ms, DataOffset = 0, DataLength = (int)ms.Position, DataBufferPool = outboundAcknowledgementMemoryStreamPool, IsReliable = false }); workSignal.Set(); }
private async Task SendReliableMultipartPacketAsync(Guid destination, PacketDto packet) { using (var ms = new MemoryStream()) { await AsyncSerialize.ToAsync(ms, packet).ConfigureAwait(false); var payloadSize = ms.Position; // message id necessary for reassembly of chunks var multiPartMessageId = Guid.NewGuid(); var chunkCount = (int)((payloadSize - 1) / UdpConstants.kMultiPartChunkSize + 1); var chunks = Util.Generate( chunkCount, chunkIndex => { var startIndexInclusive = UdpConstants.kMultiPartChunkSize * chunkIndex; var endIndexExclusive = Math.Min(payloadSize, startIndexInclusive + UdpConstants.kMultiPartChunkSize); return(new MultiPartChunkDto { Body = ms.GetBuffer(), BodyLength = (int)(endIndexExclusive - startIndexInclusive), BodyOffset = startIndexInclusive, MultiPartMessageId = multiPartMessageId, ChunkCount = chunkCount, ChunkIndex = chunkIndex }); }); logger.Info($"Splitting large payload into {chunks.Length} chunks."); await Task.WhenAll( Util.Generate( chunkCount, i => SendReliableAsync(destination, MessageDto.Create(identity.Id, destination, chunks[i])) )).ConfigureAwait(false); // const int kConcurrencyLimit = 32; //// var sync = new AsyncSemaphore(kConcurrencyLimit); // for (var i = 0; i < chunkCount; i++) { //// await sync.WaitAsync().ConfigureAwait(false); // var chunkMessage = MessageDto.Create(identity.Id, destination, chunks[i]); //// Go(async () => { // SendReliableAsync(destination, chunkMessage).Forget(); //.ConfigureAwait(false); // sync.Release(); // }).Forget(); } }
public async Task BroadcastAsync <T>(T payload) { #if DEBUG Interlocked.Increment(ref DebugRuntimeStats.out_ps); #endif var ms = outboundMemoryStreamPool.TakeObject(); Trace.Assert(ms.Position == 0); await AsyncSerialize.ToAsync(ms, payload).ConfigureAwait(false); udpClient.Broadcast( ms, 0, (int)ms.Position, () => { ms.SetLength(0); outboundMemoryStreamPool.ReturnObject(ms); #if DEBUG Interlocked.Increment(ref DebugRuntimeStats.out_ps_done); #endif }); }
public async Task SendBroadcastAsync(MessageDto message) { var packet = PacketDto.Create( identity.Id, Guid.Empty, message, false); var ms = broadcastOutboundMemoryStreamPool.TakeObject(); ms.SetLength(0); try { await AsyncSerialize.ToAsync(ms, packet).ConfigureAwait(false); } catch (NotSupportedException) { throw new InvalidOperationException("Broadcast message would surpass Courier Maximum UDP Transport Size"); } udpClient.Broadcast( ms, 0, (int)ms.Position, () => { ms.SetLength(0); broadcastOutboundMemoryStreamPool.ReturnObject(ms); }); }