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();
            }
        }
示例#4
0
        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);
            });
        }