Exemple #1
0
        private async Task AcceptLoopAsync()
        {
            while (!acceptCts.IsCancellationRequested)
            {
                try
                {
                    var socket = await socketListener.AcceptAsync().ConfigureAwait(false);

                    if (acceptCts.IsCancellationRequested)
                    {
                        return;
                    }

                    // use Math.abs to fix overflows if they ever happen.
                    int connectionId = Math.Abs(Interlocked.Increment(ref connectionIdCounter));
                    var connection   = new Connection(connectionId, socket, this);

                    logger?.LogInformation($"Connection accepted {{ connectionId={connectionId} }}.");

                    // We have a socket, setup the message stream
                    var messageStream = new EventMessageStream <TMessage>(
                        deserializer,
                        serializer,
                        new SocketDuplexMessageStream(cancellationToken => new ValueTask <Socket>(socket)),
                        msg => HandleMessagAsync(connection, msg),
                        () => HandleKeepAliveAsync(connection),
                        (ex) => HandleConnectionDisconnectAsync(connection, ex, false),
                        clientMessageStreamOptions,
                        rpcKeyResolver
                        );

                    connection.State         = connectionStateProvider(connection);
                    connection.MessageStream = messageStream;

                    if (!connections.TryAdd(connectionId, connection))
                    {
                        // TODO handle this. Shouldn't ever happen, but we should just disconnect the client.
                        var dcTask = connection.DisconnectAsync();
                        logger?.LogWarning($"Could not add connection to connection list. Disconnected connection. {{ connectionId={connectionId} }}.");
                        continue;
                    }

                    try
                    {
                        await messageStream.OpenAsync().ConfigureAwait(false);

                        logger?.LogDebug($"message-stream initialized. {{ connectionId={connectionId} }}");
                    }
                    catch (Exception ex)
                    {
                        logger?.LogError(ex, $"Error initializing message-stream. {{ connectionId={connectionId} }}.");
                        var dcTask = connection.DisconnectAsync();
                        connections.TryRemove(connectionId, out var con);
                        continue;
                    }

                    var _ = Task.Run(async() =>
                    {
                        await pendingConnectionLock.WaitAsync().ConfigureAwait(false);
                        try
                        {
                            await handleConnectionDelegate(connection).ConfigureAwait(false);

                            logger?.LogDebug($"Connection initialized {{ connectionId={connectionId} }}.");
                        }
                        catch (Exception ex)
                        {
                            logger?.LogError(ex, $"Error initializing connection. Disconnecting. {{ connectionId={connectionId} }}");
                            var dcTask = connection.DisconnectAsync();
                            connections.TryRemove(connectionId, out var con);
                        }
                        finally
                        {
                            pendingConnectionLock.Release();
                        }
                    });
                }
                catch (Exception ex)
                {
                    logger?.LogError(ex, "Exception in accept loop.");

                    bool close = await HandleAcceptExceptionAsync(ex).ConfigureAwait(false);

                    if (close)
                    {
                        logger?.LogInformation("Closing accept loop because of exception.");
                        break;
                    }
                }
            }
        }
        public async Task TestSimpleStreamAsync()
        {
            var readStream  = new MemoryStream();
            var writeStream = new MemoryStream();

            var messageStream = new MessageStream <SimpleMessage>(
                new SimpleMessageDeserializer(),
                new SimpleMessageSerializer(),
                new StreamDuplexMessageStream(readStream, writeStream)
                );

            await messageStream.OpenAsync().ConfigureAwait(false);

            // Write two messages
            await messageStream.WriteAsync(new SimpleMessage
            {
                Id    = 1,
                Value = 2
            }).ConfigureAwait(false);

            await messageStream.WriteAsync(new SimpleMessage
            {
                Id    = 2,
                Value = 4
            }).ConfigureAwait(false);

            await messageStream.CloseAsync().ConfigureAwait(false);

            // Reset the streams position so we can read in the messages
            readStream          = new MemoryStream(writeStream.ToArray());
            readStream.Position = 0;
            writeStream         = new MemoryStream();

            messageStream = new MessageStream <SimpleMessage>(
                new SimpleMessageDeserializer(),
                new SimpleMessageSerializer(),
                new StreamDuplexMessageStream(readStream, writeStream)
                );

            var receivedMessages = new List <SimpleMessage>();
            var closedTcs        = new TaskCompletionSource <bool>();

            var eventedMessageStream = new EventMessageStream <SimpleMessage>
                                       (
                new SimpleMessageDeserializer(),
                new SimpleMessageSerializer(),
                new StreamDuplexMessageStream(readStream, writeStream),
                message =>
            {
                receivedMessages.Add(message);
                return(new ValueTask <bool>());
            },
                () =>     // ignore keep alive.
            {
                return(new ValueTask());
            },
                (ex) =>     // The stream will close because the memory stream will run out of data so ignore results
            {
                closedTcs.TrySetResult(true);
                return(new ValueTask());
            }
                                       );

            await eventedMessageStream.OpenAsync().ConfigureAwait(false);

            await closedTcs.Task.ConfigureAwait(false);

            Assert.Equal(2, receivedMessages.Count);

            try
            {
                await eventedMessageStream.CloseAsync().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                // ignore, the EOF will have closed it.
            }
        }
        public async Task SocketReadsData()
        {
            ValueTask HandleConnection(SocketServer <object, object> .Connection connection)
            {
                Logger.Info($"Client connected to server: {connection.Id}");
                return(new ValueTask());
            }

            ValueTask <bool> HandleServerMessage(SocketServer <object, object> .Connection connection, object message)
            {
                Logger.Info($"Server message received: {connection.Id}:{message}");
                return(new ValueTask <bool>());
            }

            ValueTask HandleServerDisconnection(SocketServer <object, object> .Connection connection, Exception ex, bool expected)
            {
                Logger.Info($"Client disconnected from server: {connection.Id}:{expected}. {ex}");
                return(new ValueTask());
            }

            ValueTask HandleServerKeepAlive(SocketServer <object, object> .Connection connection)
            {
                Logger.Info($"Server keep handled alive for: {connection.Id}");
                return(new ValueTask());
            }

            var server = new SocketServer <object, object>(
                Deserializer,
                Serializer,
                null,
                HandleConnection,
                HandleServerMessage,
                HandleServerDisconnection,
                HandleServerKeepAlive);

            await server.ListenAsync(5463).ConfigureAwait(false);

            await Task.Delay(1000).ConfigureAwait(false);

            ValueTask <bool> HandleClientMessage(object message)
            {
                Logger.Info($"Client message received: {message}");
                return(new ValueTask <bool>());
            }

            ValueTask HandleClientDisconnection(Exception ex)
            {
                Logger.Info($"Client disconnected");
                return(new ValueTask());
            }

            ValueTask HandleClientKeepAlive()
            {
                Logger.Info($"Handling client keep alive.");
                return(new ValueTask());
            }

            var config = new SocketConfiguration
            {
                Ip   = "127.0.0.1",
                Port = 5463
            };

            var clientStream = new EventMessageStream <object>(
                Deserializer,
                Serializer,
                new SocketDuplexMessageStreamWrapper(config),
                HandleClientMessage,
                HandleClientKeepAlive,
                HandleClientDisconnection);

            await clientStream.OpenAsync().ConfigureAwait(false);

            await clientStream.WriteAsync(new PingMessage
            {
                Id = 1
            }).ConfigureAwait(false);
        }