private void HandleDataArrived(CourierNetwork network, byte[] data, int offset, int length, IPEndPoint remoteEndPoint)
        {
            using (var ms = new MemoryStream(data, offset, length))
                using (var reader = new BinaryReader(ms)) {
                    ulong magic = reader.ReadUInt64();
                    if (magic != NetworkingConstants.kMessageHeader)
                    {
                        return;
                    }

                    Guid senderId = reader.ReadGuid();
                    if (localEndpoint.Matches(senderId))
                    {
                        return;
                    }

                    var payload = pofSerializer.Deserialize(reader);
                    if (payload is CourierMessageV1)
                    {
                        HandleInboundMessage(senderId, (CourierMessageV1)payload, remoteEndPoint);
                    }
                    else if (payload is CourierAnnounceV1)
                    {
                        HandleInboundAnnounce(senderId, (CourierAnnounceV1)payload, remoteEndPoint);
                    }
                    else if (payload is CourierMessageAcknowledgeV1)
                    {
                        HandleCourierAcknowledgement(senderId, (CourierMessageAcknowledgeV1)payload);
                    }
                }
        }
        public static void EntryPoint(int i, CourierNetwork network)
        {
            ICollectionFactory      collectionFactory      = new CollectionFactory();
            ObjectPoolFactory       objectPoolFactory      = new DefaultObjectPoolFactory(collectionFactory);
            IThreadingFactory       threadingFactory       = new ThreadingFactory();
            ISynchronizationFactory synchronizationFactory = new SynchronizationFactory();
            IThreadingProxy         threadingProxy         = new ThreadingProxy(threadingFactory, synchronizationFactory);
            GuidProxy      guidProxy         = new GuidProxyImpl();
            IPofContext    courierPofContext = new DargonCourierImplPofContext();
            IPofSerializer courierSerializer = new PofSerializer(courierPofContext);
            Guid           localIdentifier   = guidProxy.NewGuid();
            var            endpoint          = new CourierEndpointImpl(courierSerializer, localIdentifier, "node" + i);
            var            networkContext    = network.Join(endpoint);

            var networkBroadcaster = new NetworkBroadcasterImpl(endpoint, networkContext, courierSerializer);
            var messageContextPool = objectPoolFactory.CreatePool(() => new UnacknowledgedReliableMessageContext());
            var unacknowledgedReliableMessageContainer = new UnacknowledgedReliableMessageContainer(messageContextPool);
            var messageDtoPool      = objectPoolFactory.CreatePool(() => new CourierMessageV1());
            var messageTransmitter  = new MessageTransmitterImpl(guidProxy, courierSerializer, networkBroadcaster, unacknowledgedReliableMessageContainer, messageDtoPool);
            var messageSender       = new MessageSenderImpl(guidProxy, unacknowledgedReliableMessageContainer, messageTransmitter);
            var acknowledgeDtoPool  = objectPoolFactory.CreatePool(() => new CourierMessageAcknowledgeV1());
            var messageAcknowledger = new MessageAcknowledgerImpl(networkBroadcaster, unacknowledgedReliableMessageContainer, acknowledgeDtoPool);
            var periodicAnnouncer   = new PeriodicAnnouncerImpl(threadingProxy, courierSerializer, endpoint, networkBroadcaster);

            periodicAnnouncer.Start();
            var periodicResender = new PeriodicResenderImpl(threadingProxy, unacknowledgedReliableMessageContainer, messageTransmitter);

            periodicResender.Start();

            ReceivedMessageFactory receivedMessageFactory = new ReceivedMessageFactoryImpl(courierSerializer);
            MessageRouter          messageRouter          = new MessageRouterImpl(receivedMessageFactory);
            var peerRegistry    = new PeerRegistryImpl(courierSerializer);
            var networkReceiver = new NetworkReceiverImpl(endpoint, networkContext, courierSerializer, messageRouter, messageAcknowledger, peerRegistry);

            networkReceiver.Initialize();

            messageRouter.RegisterPayloadHandler <string>(m => {
//            Console.WriteLine(i + ": " + m.Payload);
            });

            Thread.Sleep(3000);

            if (i == 0)
            {
                while (true)
                {
                    for (var j = 0; j < 50; j++)
                    {
                        Console.WriteLine(unacknowledgedReliableMessageContainer.GetUnsentMessagesRemaining() + " pending");
                        var stopwatch = new Stopwatch();
                        stopwatch.Start();
                        var messagesRemaining = unacknowledgedReliableMessageContainer.GetUnsentMessagesRemaining();
                        var peers             = peerRegistry.EnumeratePeers().ToArray();
                        for (var k = 0; k < 10000; k++)
                        {
                            foreach (var peer in peers)
                            {
                                messageSender.SendReliableUnicast(peer.Id, "Message " + j + " hello from " + i + ", " + peer.Id, MessagePriority.Low);
                            }
                        }
                        var messagesAcked = unacknowledgedReliableMessageContainer.GetUnsentMessagesRemaining() - messagesRemaining + 10000;
                        Console.WriteLine("Got " + (messagesAcked * peers.Length) + " acks in " + stopwatch.ElapsedMilliseconds + "ms (" + (messagesAcked * peers.Length / stopwatch.Elapsed.TotalSeconds) + " per second) " + messagesRemaining + " remaining");
                        Thread.Sleep(1);
                    }

                    for (var j = 0; j < 1000; j++)
                    {
                        Console.WriteLine(unacknowledgedReliableMessageContainer.GetUnsentMessagesRemaining() + " pending");
                        Thread.Sleep(1);
                    }
                }
            }
        }
 private void InvokeDataArrived(CourierNetwork network, byte[] data, int offset, int length, IPEndPoint remoteEndpoint)
 {
     DataArrived?.Invoke(network, data, offset, length, remoteEndpoint);
 }